HeaderSearch.h revision 49c1f4aa2a6c360d25d605004ec3c4affd62db77
15f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===--- HeaderSearch.h - Resolve Header File Locations ---------*- C++ -*-===// 25f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 35f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// The LLVM Compiler Infrastructure 45f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 50bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// This file is distributed under the University of Illinois Open Source 60bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// License. See LICENSE.TXT for details. 75f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 85f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===// 95f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// This file defines the HeaderSearch interface. 115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===// 135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#ifndef LLVM_CLANG_LEX_HEADERSEARCH_H 155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#define LLVM_CLANG_LEX_HEADERSEARCH_H 165f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 175f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "clang/Lex/DirectoryLookup.h" 185f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "llvm/ADT/StringMap.h" 195f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include <vector> 205f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencernamespace clang { 225f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerclass FileEntry; 235f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerclass FileManager; 245f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerclass IdentifierInfo; 255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 265f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 275f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// HeaderSearch - This class encapsulates the information needed to find the 285f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// file referenced by a #include or #include_next, (sub-)framework lookup, etc. 295f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerclass HeaderSearch { 305f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer FileManager &FileMgr; 315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// #include search path information. Requests for #include "x" search the 335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// directory of the #including file first, then each directory in SearchDirs 345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// consequtively. Requests for <x> search the current dir first, then each 355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// directory in SearchDirs, starting at SystemDirIdx, consequtively. If 365f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// NoCurDirSearch is true, then the check for the file in the current 375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// directory is supressed. 385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer std::vector<DirectoryLookup> SearchDirs; 395f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned SystemDirIdx; 405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer bool NoCurDirSearch; 415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 425f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// PreFileInfo - The preprocessor keeps track of this information for each 435f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// file that is #included. 445f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer struct PerFileInfo { 455f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// isImport - True if this is a #import'd or #pragma once file. 465f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer bool isImport : 1; 475f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 485f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// DirInfo - Keep track of whether this is a system header, and if so, 495f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// whether it is C++ clean or not. This can be set by the include paths or 505f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// by #pragma gcc system_header. 515f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer DirectoryLookup::DirType DirInfo : 2; 525f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 535f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// NumIncludes - This is the number of times the file has been included 545f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// already. 555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned short NumIncludes; 565f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// ControllingMacro - If this file has a #ifndef XXX (or equivalent) guard 585f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// that protects the entire contents of the file, this is the identifier 595f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// for the macro that controls whether or not it has any effect. 605f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const IdentifierInfo *ControllingMacro; 615f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 625f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer PerFileInfo() : isImport(false), DirInfo(DirectoryLookup::NormalHeaderDir), 635f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer NumIncludes(0), ControllingMacro(0) {} 645f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer }; 655f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// FileInfo - This contains all of the preprocessor-specific data about files 675f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// that are included. The vector is indexed by the FileEntry's UID. 685f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// 695f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer std::vector<PerFileInfo> FileInfo; 705f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 719960ae8ecfa2c4278dac708a02e463f83fdf17e8Chris Lattner /// LookupFileCache - This is keeps track of each lookup performed by 729960ae8ecfa2c4278dac708a02e463f83fdf17e8Chris Lattner /// LookupFile. The first part of the value is the starting index in 739960ae8ecfa2c4278dac708a02e463f83fdf17e8Chris Lattner /// SearchDirs that the cached search was performed from. If there is a hit 749960ae8ecfa2c4278dac708a02e463f83fdf17e8Chris Lattner /// and this value doesn't match the current query, the cache has to be 759960ae8ecfa2c4278dac708a02e463f83fdf17e8Chris Lattner /// ignored. The second value is the entry in SearchDirs that satisfied the 769960ae8ecfa2c4278dac708a02e463f83fdf17e8Chris Lattner /// query. 779960ae8ecfa2c4278dac708a02e463f83fdf17e8Chris Lattner llvm::StringMap<std::pair<unsigned, unsigned> > LookupFileCache; 789960ae8ecfa2c4278dac708a02e463f83fdf17e8Chris Lattner 799960ae8ecfa2c4278dac708a02e463f83fdf17e8Chris Lattner 805f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// FrameworkMap - This is a collection mapping a framework or subframework 815f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// name like "Carbon" to the Carbon.framework directory. 825f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer llvm::StringMap<const DirectoryEntry *> FrameworkMap; 835f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 84822da61b74ce14e89b3fa8774db18c833aa5748bChris Lattner /// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing 85822da61b74ce14e89b3fa8774db18c833aa5748bChris Lattner /// headermaps. This vector owns the headermap. 86822da61b74ce14e89b3fa8774db18c833aa5748bChris Lattner std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps; 87822da61b74ce14e89b3fa8774db18c833aa5748bChris Lattner 885f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Various statistics we track for performance analysis. 895f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned NumIncluded; 905f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned NumMultiIncludeFileOptzn; 915f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned NumFrameworkLookups, NumSubFrameworkLookups; 9249c1f4aa2a6c360d25d605004ec3c4affd62db77Steve Naroff 9349c1f4aa2a6c360d25d605004ec3c4affd62db77Steve Naroff // HeaderSearch doesn't support default or copy construction. 9449c1f4aa2a6c360d25d605004ec3c4affd62db77Steve Naroff explicit HeaderSearch(); 9549c1f4aa2a6c360d25d605004ec3c4affd62db77Steve Naroff explicit HeaderSearch(const HeaderSearch&); 9649c1f4aa2a6c360d25d605004ec3c4affd62db77Steve Naroff void operator=(const HeaderSearch&); 975f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerpublic: 985f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer HeaderSearch(FileManager &FM); 99822da61b74ce14e89b3fa8774db18c833aa5748bChris Lattner ~HeaderSearch(); 1005f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1015f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer FileManager &getFileMgr() const { return FileMgr; } 1025f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1035f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// SetSearchPaths - Interface for setting the file search paths. 1045f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// 1055f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer void SetSearchPaths(const std::vector<DirectoryLookup> &dirs, 1065f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned systemDirIdx, bool noCurDirSearch) { 1075f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer SearchDirs = dirs; 1085f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer SystemDirIdx = systemDirIdx; 1095f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer NoCurDirSearch = noCurDirSearch; 1109960ae8ecfa2c4278dac708a02e463f83fdf17e8Chris Lattner //LookupFileCache.clear(); 1115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer } 1125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// ClearFileInfo - Forget everything we know about headers so far. 1145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer void ClearFileInfo() { 1155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer FileInfo.clear(); 1165f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer } 1175f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1185f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file, 1195f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// return null on failure. isAngled indicates whether the file reference is 1205f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// a <> reference. If successful, this returns 'UsedDir', the 1215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// DirectoryLookup member the file was found in, or null if not applicable. 1225f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// If CurDir is non-null, the file was found in the specified directory 1235f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// search location. This is used to implement #include_next. CurFileEnt, if 1245f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// non-null, indicates where the #including file is, in case a relative 1255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// search is needed. 1265f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const FileEntry *LookupFile(const char *FilenameStart, 1275f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *FilenameEnd, bool isAngled, 1285f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const DirectoryLookup *FromDir, 1295f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const DirectoryLookup *&CurDir, 1305f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const FileEntry *CurFileEnt); 1315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// LookupSubframeworkHeader - Look up a subframework for the specified 1335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from 1345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox 1355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// is a subframework within Carbon.framework. If so, return the FileEntry 1365f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// for the designated file, otherwise return null. 1375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const FileEntry *LookupSubframeworkHeader(const char *FilenameStart, 1385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *FilenameEnd, 1395f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const FileEntry *RelativeFileEnt); 1405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 141afded5bbb85607023c710c3d6a96c372feb84d7fChris Lattner /// LookupFrameworkCache - Look up the specified framework name in our 142afded5bbb85607023c710c3d6a96c372feb84d7fChris Lattner /// framework cache, returning the DirectoryEntry it is in if we know, 143afded5bbb85607023c710c3d6a96c372feb84d7fChris Lattner /// otherwise, return null. 144afded5bbb85607023c710c3d6a96c372feb84d7fChris Lattner const DirectoryEntry *&LookupFrameworkCache(const char *FWNameStart, 145afded5bbb85607023c710c3d6a96c372feb84d7fChris Lattner const char *FWNameEnd) { 146afded5bbb85607023c710c3d6a96c372feb84d7fChris Lattner return FrameworkMap.GetOrCreateValue(FWNameStart, FWNameEnd).getValue(); 147afded5bbb85607023c710c3d6a96c372feb84d7fChris Lattner } 148afded5bbb85607023c710c3d6a96c372feb84d7fChris Lattner 1495f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// ShouldEnterIncludeFile - Mark the specified file as a target of of a 1505f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// #include, #include_next, or #import directive. Return false if #including 1515f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// the file will have no effect or true if we should include it. 1525f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer bool ShouldEnterIncludeFile(const FileEntry *File, bool isImport); 1535f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1545f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// getFileDirFlavor - Return whether the specified file is a normal header, 1565f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// a system header, or a C++ friendly system header. 1575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer DirectoryLookup::DirType getFileDirFlavor(const FileEntry *File) { 1585f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return getFileInfo(File).DirInfo; 1595f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer } 1605f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1615f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// MarkFileIncludeOnce - Mark the specified file as a "once only" file, e.g. 1625f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// due to #pragma once. 1635f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer void MarkFileIncludeOnce(const FileEntry *File) { 1645f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer getFileInfo(File).isImport = true; 1655f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer } 1665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1675f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// MarkFileSystemHeader - Mark the specified fiel as a system header, e.g. 1685f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// due to #pragma GCC system_header. 1695f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer void MarkFileSystemHeader(const FileEntry *File) { 1705f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer getFileInfo(File).DirInfo = DirectoryLookup::SystemHeaderDir; 1715f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer } 1725f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 17325bfcb927d9169ea675ce6e98d8992efceeb0e42Chris Lattner /// IncrementIncludeCount - Increment the count for the number of times the 17425bfcb927d9169ea675ce6e98d8992efceeb0e42Chris Lattner /// specified FileEntry has been entered. 17525bfcb927d9169ea675ce6e98d8992efceeb0e42Chris Lattner void IncrementIncludeCount(const FileEntry *File) { 17625bfcb927d9169ea675ce6e98d8992efceeb0e42Chris Lattner ++getFileInfo(File).NumIncludes; 17725bfcb927d9169ea675ce6e98d8992efceeb0e42Chris Lattner } 17825bfcb927d9169ea675ce6e98d8992efceeb0e42Chris Lattner 1795f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// SetFileControllingMacro - Mark the specified file as having a controlling 1805f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// macro. This is used by the multiple-include optimization to eliminate 1815f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// no-op #includes. 1825f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer void SetFileControllingMacro(const FileEntry *File, 1835f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const IdentifierInfo *ControllingMacro) { 1845f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer getFileInfo(File).ControllingMacro = ControllingMacro; 1855f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer } 1865f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 187822da61b74ce14e89b3fa8774db18c833aa5748bChris Lattner /// CreateHeaderMap - This method returns a HeaderMap for the specified 188822da61b74ce14e89b3fa8774db18c833aa5748bChris Lattner /// FileEntry, uniquing them through the the 'HeaderMaps' datastructure. 1891bfd4a6313ea8ebf710c46c10111732cc65d51f6Chris Lattner const HeaderMap *CreateHeaderMap(const FileEntry *FE); 190822da61b74ce14e89b3fa8774db18c833aa5748bChris Lattner 191afded5bbb85607023c710c3d6a96c372feb84d7fChris Lattner void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; } 192afded5bbb85607023c710c3d6a96c372feb84d7fChris Lattner 1935f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer void PrintStats(); 1945f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerprivate: 1955f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1965f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// getFileInfo - Return the PerFileInfo structure for the specified 1975f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// FileEntry. 1985f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer PerFileInfo &getFileInfo(const FileEntry *FE); 1995f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}; 2005f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2015f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer} // end namespace clang 2025f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2035f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#endif 204