kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/docs/modeling-libraries.txt (about)

     1  // Copyright 2015 The Kythe Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //   http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  = Modeling a Command-Line Flag Library
    16  
    17  We record https://gflags.github.io/gflags/[gflags]-specific information by
    18  defining a custom node kind.
    19  
    20  Tools can record arbitrary library- or project-specific information in the
    21  Kythe graph. We recently added support for the gflags command line flags parsing
    22  library to demonstrate this. gflags command-line flags are declared and
    23  defined in $$C++$$ using macros:
    24  
    25  [source,c]
    26  ----
    27  DECLARE_bool(secure);
    28  DEFINE_string(address, "127.0.0.1", "Listen on this address.");
    29  
    30  (...)
    31  
    32  auto my_uri = (FLAGS_secure ? "https://" : "http://") + FLAGS_address + ":80";
    33  ----
    34  
    35  The Kythe $$C++$$ indexer will record that the flag variable `FLAGS_address` is
    36  defined inside the macro. One can go further and treat the flag being defined as
    37  a first-class object. In this view, the `DEFINE_string` macro defines a new flag
    38  object to which `FLAGS_address` refers. The data about the underlying $$C++$$
    39  variables remain in the graph, but now we have added some library-specific
    40  semantic information.
    41  
    42  In our model of the gflags library, each flag definition or declaration gives
    43  rise to a node with kind `google/gflag`. We add this kind underneath the
    44  `google/` prefix to avoid polluting the base namespace of Kythe nodes. Like
    45  link:/docs/schema#variable[variables], gflags can be definitions (via `DEFINE_`)
    46  or incomplete (via `DECLARE_`); they are also link:/docs/schema#named[named]
    47  with the identifier that the programmer writes down in the macro
    48  invocation. This name is distinct from the name of the variable that the macro
    49  creates. Later references to that variable are also references to the flag with
    50  which it is associated.
    51  
    52  With a complete implementation, the following verifier test should pass:
    53  
    54  [source,c]
    55  ----
    56  // Checks that we can complete a string flag decl.
    57  #include "flags_string.h"
    58    // This header contains these lines:
    59    // #include "gflags.h"
    60    // DECLARE_string(stringflag);
    61  //- StringFlagDeclAnchor defines StringFlagDecl
    62  //- StringFlagDecl.complete incomplete
    63  //- StringFlagDecl.node/kind google/gflag
    64  //- @stringflag defines StringFlag
    65  //- StringFlag.complete definition
    66  //- StringFlag.node/kind google/gflag
    67  //- @stringflag completes StringFlagDecl
    68  DEFINE_string(stringflag, "gnirts", "rtsgni");
    69  //- @FLAGS_stringflag ref StringFlag
    70  //- @FLAGS_stringflag ref FlagVar
    71  //- FlagVar.node/kind variable
    72  auto s = FLAGS_stringflag;
    73  ----
    74  
    75  The actual business of finding and labeling flags requires some work
    76  with Clang's syntax tree. We define an auxiliary function that, given
    77  a variable declaration (a `clang::VarDecl`), walks around in the tree
    78  to try to find the location of the flag identifier in the macro that
    79  caused that declaration. Of course, not many variables will be associated
    80  with flags. In that case, this routine (`GetVarDeclFlagDeclLoc` in
    81  `//kythe/cxx/indexer/cxx/IndexerLibrarySupport.cc`) returns a result that is
    82  marked invalid. Since this function will be called once per variable declaration
    83  discovered by the indexer as it traverses the syntax tree, we take extra care to
    84  quickly reject variables that could not possibly be flags (such as variables
    85  that do not begin with "FLAGS_" or variables that were not declared inside a
    86  macro).
    87  
    88  We now have our graph representation and a procedure to collect the information
    89  necessary to generate it. Now, by using the $$C++$$ indexer's `LibrarySupport`
    90  interface, we can listen for variable declarations and references to check for
    91  the ones for which we need to emit flag annotations. This interface differs
    92  from Clang's `RecursiveASTVisitor` as it provides Kythe-specific information
    93  as well as pointers into the AST; for example, it will provide VNames for
    94  the variables it encounters. Since every flag is associated with at least
    95  one variable definition or declaration (which is, in turn, not associated
    96  with any other flag), and because the VName for that variable def/decl is
    97  a globally-unique identifier, we can use it as a base for the name of the
    98  `google/gflag` node we will create. In practice, building this derived name
    99  requires only that we add a prefix to the `signature` component of the VName
   100  (and by convention, we'll use `google/gflag#`).
   101  
   102  With this logic in place, we can check our verifier test above (and write
   103  some other ones, too). The new data in the graph are available to any Kythe
   104  tool. These tools are free to ignore it, to present it as generic graph
   105  relationships, or to interpret it with special knowledge about what being a
   106  `google/gflag` implies.