CheckerContext.h revision 4e4d08403ca5cfd4d558fa2936215d3a4e5a528d
16acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//== CheckerContext.h - Context info for path-sensitive checkers--*- C++ -*--=// 26acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// 36acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// The LLVM Compiler Infrastructure 46acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// 56acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// This file is distributed under the University of Illinois Open Source 66acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// License. See LICENSE.TXT for details. 76acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// 86acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//===----------------------------------------------------------------------===// 96acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// 106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// This file defines CheckerContext that provides contextual info for 116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// path-sensitive checkers. 126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// 136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//===----------------------------------------------------------------------===// 146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#ifndef LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT 166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT 176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennnamespace clang { 216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennnamespace ento { 226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennclass CheckerContext { 246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExprEngine &Eng; 256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// The current exploded(symbolic execution) graph node. 266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *Pred; 276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// The flag is true if the (state of the execution) has been modified 286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// by the checker using this context. For example, a new transition has been 296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// added or a bug report issued. 306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn bool Changed; 316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// The tagged location, which is used to generate all new nodes. 326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn const ProgramPoint Location; 336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn NodeBuilder &NB; 346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennpublic: 366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn CheckerContext(NodeBuilder &builder, 376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExprEngine &eng, 386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *pred, 396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn const ProgramPoint &loc) 406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn : Eng(eng), 416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn Pred(pred), 426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn Changed(false), 436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn Location(loc), 446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn NB(builder) { 456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn assert(Pred->getState() && 466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn "We should not call the checkers on an empty state."); 476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn AnalysisManager &getAnalysisManager() { 506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Eng.getAnalysisManager(); 516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ConstraintManager &getConstraintManager() { 546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Eng.getConstraintManager(); 556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn StoreManager &getStoreManager() { 586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Eng.getStoreManager(); 596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Returns the previous node in the exploded graph, which includes 626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// the state of the program before the checker ran. Note, checkers should 636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// not retain the node in their state since the nodes might get invalidated. 646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *getPredecessor() { return Pred; } 656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ProgramStateRef getState() const { return Pred->getState(); } 666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Check if the checker changed the state of the execution; ex: added 686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// a new transition or a bug report. 696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn bool isDifferent() { return Changed; } 706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Returns the number of times the current block has been visited 726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// along the analyzed path. 736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn unsigned getCurrentBlockCount() const { 746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return NB.getContext().getCurrentBlockCount(); 756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ASTContext &getASTContext() { 786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Eng.getContext(); 796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn const LangOptions &getLangOpts() const { 826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Eng.getContext().getLangOpts(); 836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn const LocationContext *getLocationContext() const { 866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Pred->getLocationContext(); 876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn BugReporter &getBugReporter() { 906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Eng.getBugReporter(); 916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn SourceManager &getSourceManager() { 946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return getBugReporter().getSourceManager(); 956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn SValBuilder &getSValBuilder() { 986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Eng.getSValBuilder(); 996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn SymbolManager &getSymbolManager() { 1026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return getSValBuilder().getSymbolManager(); 1036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn bool isObjCGCEnabled() const { 1066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Eng.isObjCGCEnabled(); 1076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ProgramStateManager &getStateManager() { 1106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Eng.getStateManager(); 1116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn AnalysisDeclContext *getCurrentAnalysisDeclContext() const { 1146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Pred->getLocationContext()->getAnalysisDeclContext(); 1156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Generates a new transition in the program state graph 1186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// (ExplodedGraph). Uses the default CheckerContext predecessor node. 1196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// 1206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// @param State The state of the generated node. 1216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// @param Tag The tag is used to uniquely identify the creation site. If no 1226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// tag is specified, a default tag, unique to the given checker, 1236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// will be used. Tags are used to prevent states generated at 1246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// different sites from caching out. 1256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *addTransition(ProgramStateRef State, 1266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn const ProgramPointTag *Tag = 0) { 1276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return addTransitionImpl(State, false, 0, Tag); 1286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Generates a default transition (containing checker tag but no 1316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// checker state changes). 1326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *addTransition() { 1336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return addTransition(getState()); 1346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Generates a new transition with the given predecessor. 1376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// Allows checkers to generate a chain of nodes. 1386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// 1396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// @param State The state of the generated node. 1406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// @param Pred The transition will be generated from the specified Pred node 1416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// to the newly generated node. 1426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// @param Tag The tag to uniquely identify the creation site. 1436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// @param IsSink Mark the new node as sink, which will stop exploration of 1446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// the given path. 1456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *addTransition(ProgramStateRef State, 1466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *Pred, 1476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn const ProgramPointTag *Tag = 0, 1486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn bool IsSink = false) { 1496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return addTransitionImpl(State, IsSink, Pred, Tag); 1506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Generate a sink node. Generating sink stops exploration of the 1536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// given path. 1546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *generateSink(ProgramStateRef state = 0) { 1556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return addTransitionImpl(state ? state : getState(), true); 1566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Emit the diagnostics report. 1596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn void EmitReport(BugReport *R) { 1606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn Changed = true; 1616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn Eng.getBugReporter().EmitReport(R); 1626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Get the declaration of the called function (path-sensitive). 1656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn const FunctionDecl *getCalleeDecl(const CallExpr *CE) const; 1666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Get the name of the called function (path-sensitive). 1686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn StringRef getCalleeName(const FunctionDecl *FunDecl) const; 1696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Get the name of the called function (path-sensitive). 1716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn StringRef getCalleeName(const CallExpr *CE) const { 1726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn const FunctionDecl *FunDecl = getCalleeDecl(CE); 1736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return getCalleeName(FunDecl); 1746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 1756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// Given a function declaration and a name checks if this is a C lib 1776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// function with the given name. 1786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name); 1796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name, 1806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ASTContext &Context); 1816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \brief Depending on wither the location corresponds to a macro, return 1836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// either the macro name or the token spelling. 1846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// 1856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// This could be useful when checkers' logic depends on whether a function 1866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// is called with a given macro argument. For example: 1876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// s = socket(AF_INET,..) 1886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// If AF_INET is a macro, the result should be treated as a source of taint. 1896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// 1906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName(). 1916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn StringRef getMacroNameOrSpelling(SourceLocation &Loc); 1926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 1936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennprivate: 1946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *addTransitionImpl(ProgramStateRef State, 1956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn bool MarkAsSink, 1966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *P = 0, 1976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn const ProgramPointTag *Tag = 0) { 1986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn if (!State || (State == Pred->getState() && !Tag && !MarkAsSink)) 1996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return Pred; 2006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 2016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn Changed = true; 2026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn ExplodedNode *node = NB.generateNode(Tag ? Location.withTag(Tag) : Location, 2036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn State, 2046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn P ? P : Pred, MarkAsSink); 2056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn return node; 2066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn } 2076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}; 2086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 2096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/// \brief A helper class which wraps a boolean value set to false by default. 2106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstruct DefaultBool { 2116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn bool Val; 2126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn DefaultBool() : Val(false) {} 2136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn operator bool() const { return Val; } 2146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn DefaultBool &operator=(bool b) { Val = b; return *this; } 2156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}; 2166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 2176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn} // end GR namespace 2186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 2196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn} // end clang namespace 2206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn 2216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#endif 2226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn