void HeaderTagger::addHeaderForDecl(const core::NodePtr& node, const clang::Decl* decl, bool attachUserDefined) const { // check whether there is a declaration at all if (!decl) return; // the node was already annotated, what is the point of doint it again? if (insieme::annotations::c::hasIncludeAttached(node)) return; if (VLOG_IS_ON(2)){ std::string name("UNNAMED"); if (const clang::NamedDecl* nmd = llvm::dyn_cast<clang::NamedDecl>(decl)) name = nmd->getQualifiedNameAsString(); VLOG(2) << "Searching header for: " << node << " of type " << node->getNodeType() << " [clang: " << name << "]" ; } string fileName = getTopLevelInclude(decl->getLocation()); // file must be a header file if (!isHeaderFile(fileName)) { VLOG(2) << "'" << fileName << "' not a headerfile"; return; // not to be attached } // do not add headers for external declarations unless those are within the std-library if (const clang::FunctionDecl* funDecl = llvm::dyn_cast<clang::FunctionDecl>(decl)) { // TODO: this is just based on integration tests - to make them work, no real foundation :( if( funDecl->isExternC() && !(isStdLibHeader(fileName) || isIntrinsicHeader(fileName)) ) return; } // get absolute path of header file fs::path header = fs::canonical(fileName); if (auto oclHeader = isOCLHeader(header)){ VLOG(2) << "OCL header to be attached: " << oclHeader; insieme::annotations::c::attachInclude(node, *oclHeader); return; }if( auto stdLibHeader = toStdLibHeader(header) ) { header = *stdLibHeader; } else if (auto interceptedLibHeader = toInterceptedLibHeader(header) ) { header = *interceptedLibHeader; } else if( auto intrinsicHeader = toIntrinsicHeader(header) ) { header = *intrinsicHeader; } else if (auto userLibHeader = toUserLibHeader(header) ) { if(attachUserDefined ) { header = *userLibHeader; } else { return; } } VLOG(2) << " header to be attached: " << header.string(); // use resulting header insieme::annotations::c::attachInclude(node, header.string()); }
bool HeaderTagger::isStdLibHeader(const clang::SourceLocation& loc) const { if(!loc.isValid()) { return false; } auto fit = isStdCache.find(sm.getFileID(loc)); if(fit != isStdCache.end()) { return fit->second.second; } std::string filename = sm.getPresumedLoc(loc).getFilename(); bool isSys = isStdLibHeader(filename); isStdCache[sm.getFileID(loc)] = {filename, isSys}; return isSys; }
bool HeaderTagger::isDefinedInSystemHeader (const clang::Decl* decl) const { return isStdLibHeader(decl->getLocation()); }
string HeaderTagger::getTopLevelInclude(const clang::SourceLocation& includeLocation) const{ // if it is a dead end if (!includeLocation.isValid()) { return ""; } auto toFilename = [&] (const clang::SourceLocation& loc) { return sm.getPresumedLoc(loc).getFilename(); }; // get the presumed location (whatever this is, ask clang) ... // ~ ploc represents the file were includeLocation is located clang::PresumedLoc ploc = sm.getPresumedLoc(includeLocation); // .. and retrieve the associated include // ~ from where the file ploc represents was included clang::SourceLocation includingLocation = ploc.getIncludeLoc(); // check whether the stack can be continued if (!includingLocation.isValid()) { return ""; // this happens when element is declared in c / cpp file => no header } // ~ pIncludeLoc represents the file were includLoc is located clang::PresumedLoc pIncludeLoc = sm.getPresumedLoc(includingLocation); if( isInjectedHeader(pIncludeLoc) ){ //the header was injected -- has no valid filename ("<command line">) return ""; } //******************* // // travel down until we are at the sourcefile then work up again // if userProvided header, we need to go further // if userSearchPath/systemSearch path we need to include de header // //******************* // descent further as long as we have a header file as presumed include includeLocation if ( isHeaderFile(toFilename(includingLocation) )) { // check if last include was in the search path and next is not, // this case is a system header included inside of a programmer include chain // BUT if both are still in the search path, continue cleaning the include if (isStdLibHeader(includeLocation) && !isStdLibHeader(includingLocation)){ if(!isIntrinsicHeader(toFilename(includingLocation))) { return ploc.getFilename(); } } if (isInterceptedLibHeader(includeLocation) && !isInterceptedLibHeader(includingLocation)){ if(!isIntrinsicHeader(toFilename(includingLocation))) { return ploc.getFilename(); } } if (isUserLibHeader(includeLocation) && !isUserLibHeader(includingLocation)){ if(!isIntrinsicHeader(toFilename(includingLocation))) { return ploc.getFilename(); } } return getTopLevelInclude(includingLocation); } // we already visited all the headers and we are in the .c/.cpp file if (isHeaderFile(ploc.getFilename())) { if(isIntrinsicHeader(ploc.getFilename())) { return ploc.getFilename(); } if (isStdLibHeader(ploc.getFilename()) ) { return ploc.getFilename(); // this happens when header file is included straight in the code } if (isInterceptedLibHeader(ploc.getFilename())) { return ploc.getFilename(); // this happens when header file is included straight in the code } if (isUserLibHeader(ploc.getFilename())) { return ploc.getFilename(); } return ""; // this happens when is declared in a header which is not system header } /* // we already visited all the headers and we are in the .c/.cpp file if (!isHeaderFile(sm.getPresumedLoc(includeLoc).getFilename())) { return ploc.getFilename(); } */ return ""; }