trick/trick_source/codegen/Interface_Code_Gen/CommentSaver.cpp
Alex Lin 447585ad16 ICG processing files it is supposed to skip
We pull file names out of the clang infrastructure to match where
classes are defined.  We use the file name to pull comments and find
and process Trick header comments.  Up to now clang gave us the realpath
of files and when we looked up comments we already had the realpath and
everything worked.  In clang 3.6 in some places we are not getting the
realpath anymore which confuses ICG.  Added code to get the realpath of
any file name we use throughout the code.

refs #167
2016-02-04 15:43:14 -06:00

268 lines
10 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
#include <sstream>
#include <regex.h>
#include <algorithm>
#include "clang/Basic/FileManager.h"
#include "CommentSaver.hh"
#include "Utilities.hh"
CommentSaver::CommentSaver(clang::CompilerInstance & in_ci , HeaderSearchDirs & in_hsd ) : ci(in_ci) , hsd(in_hsd) {}
bool CommentSaver::HandleComment(clang::Preprocessor &PP, clang::SourceRange Comment) {
//Comment.getBegin().dump(sm) ;
if ( isInUserOrTrickCode( ci , Comment.getBegin() , hsd ) ) {
std::string file_name = ci.getSourceManager().getBufferName(Comment.getBegin()) ;
char * resolved_path = almostRealPath( file_name.c_str() ) ;
if ( resolved_path != NULL ) {
unsigned int line_no = ci.getSourceManager().getSpellingLineNumber(Comment.getBegin()) ;
comment_map[std::string(resolved_path)][line_no] = Comment ;
free(resolved_path) ;
}
}
// returning false means we did not push any text back to the stream for further reads.
return false ;
}
std::string CommentSaver::getComment( clang::SourceRange sr ) {
if ( sr.isValid() ) {
/* fsl_begin and fsl_end are two pointers into the header file. We want the text between the two pointers. */
clang::FullSourceLoc fsl_begin(sr.getBegin() , ci.getSourceManager()) ;
clang::FullSourceLoc fsl_end(sr.getEnd() , ci.getSourceManager()) ;
std::string comment_text( fsl_begin.getCharacterData() ,
(size_t)(fsl_end.getCharacterData() - fsl_begin.getCharacterData())) ;
return comment_text ;
}
/* return an empty string if no comment found on this line of the file. */
return std::string() ;
}
std::string CommentSaver::getComment( std::string file_name , unsigned int line_no ) {
return getComment(comment_map[file_name][line_no]) ;
}
std::string CommentSaver::getTrickHeaderComment( std::string file_name ) {
std::map < unsigned int , clang::SourceRange >::iterator cit ;
std::string ret ;
char * resolved_path = almostRealPath( file_name.c_str() ) ;
if ( resolved_path != NULL ) {
if ( trick_header_comments.find(resolved_path) == trick_header_comments.end() ) {
trick_header_comments[resolved_path] = std::string() ;
for ( cit = comment_map[resolved_path].begin() ; cit != comment_map[resolved_path].end() ; cit++ ) {
std::string comment_str = getComment((*cit).second) ;
if ( comment_str.find("@trick_parse") != std::string::npos or
comment_str.find("\\trick_parse") != std::string::npos ) {
trick_header_comments[resolved_path] = getComment((*cit).second) ;
break ;
} else {
std::transform(comment_str.begin(), comment_str.end(), comment_str.begin(), ::toupper) ;
if ( comment_str.find("PURPOSE") != std::string::npos ) {
trick_header_comments[resolved_path] = getComment((*cit).second) ;
break ;
}
}
}
}
ret = trick_header_comments[resolved_path] ;
free(resolved_path) ;
}
return ret ;
}
void CommentSaver::getICGField( std::string file_name ) {
/* default the icg_no flags to false */
icg_no_found[file_name] = false ;
icg_no_comment_found[file_name] = false ;
std::string th_str = getTrickHeaderComment(file_name) ;
if ( ! th_str.empty() ) {
size_t trick_parse_keyword ;
if ( (trick_parse_keyword = th_str.find("trick_parse")) != std::string::npos ) {
size_t trick_parse_everything = th_str.find("everything", trick_parse_keyword) ;
size_t trick_parse_attributes = th_str.find("attributes", trick_parse_keyword) ;
size_t trick_parse_dep_only = th_str.find("dependencies_only", trick_parse_keyword) ;
size_t closing_brace = th_str.find("}", trick_parse_keyword) ;
if ( closing_brace != std::string::npos ) {
if ( trick_parse_everything != std::string::npos and
trick_parse_everything < closing_brace ) {
icg_no_comment_found[file_name] = false ;
icg_no_found[file_name] = false ;
} else if ( trick_parse_attributes != std::string::npos and
trick_parse_attributes < closing_brace ) {
icg_no_comment_found[file_name] = true ;
icg_no_found[file_name] = false ;
} else if ( trick_parse_dep_only != std::string::npos and
trick_parse_dep_only < closing_brace ) {
icg_no_comment_found[file_name] = false ;
icg_no_found[file_name] = true ;
} else {
std::cout << file_name << ": trick_parse directive found but no argument matched." << std::endl ;
std::cout << "Valid arguments are (everything|attributes|dependencies_only)" << std::endl ;
exit(-1) ;
}
}
} else {
std::transform(th_str.begin(), th_str.end(), th_str.begin(), ::toupper) ;
int ret ;
regex_t reg_expr ;
regmatch_t pmatch[10] ;
memset(pmatch , 0 , sizeof(pmatch)) ;
/* POSIX regular expressions are always greedy, making our job harder.
We have to use several regular expressions to get the types. This was
so much easier in perl! */
/* find the ICG field */
ret = regcomp( &reg_expr , "(ICG:)" , REG_EXTENDED | REG_ICASE ) ;
ret = regexec( &reg_expr , th_str.c_str() , 10 , pmatch , 0 ) ;
regfree(&reg_expr) ;
if ( ret != 0 ) {
return ;
}
th_str = th_str.substr(pmatch[1].rm_eo) ;
/* find the end of the ICG field */
memset(pmatch , 0 , sizeof(pmatch)) ;
ret = regcomp( &reg_expr , "(\\))" , REG_EXTENDED ) ;
ret = regexec( &reg_expr , th_str.c_str() , 10 , pmatch , 0 ) ;
regfree(&reg_expr) ;
if ( ret != 0 ) {
return ;
}
th_str = th_str.substr(0 , pmatch[1].rm_so) ;
/* test for NoComment */
memset(pmatch , 0 , sizeof(pmatch)) ;
ret = regcomp( &reg_expr , "(NOCOMMENT)$" , REG_EXTENDED ) ;
ret = regexec( &reg_expr , th_str.c_str() , 10 , pmatch , 0 ) ;
regfree(&reg_expr) ;
if ( ret == 0 ) {
icg_no_comment_found[file_name] = true ;
}
/* test for No */
memset(pmatch , 0 , sizeof(pmatch)) ;
ret = regcomp( &reg_expr , "(NO)$" , REG_EXTENDED ) ;
ret = regexec( &reg_expr , th_str.c_str() , 10 , pmatch , 0 ) ;
regfree(&reg_expr) ;
if ( ret == 0 ) {
icg_no_found[file_name] = true ;
icg_no_comment_found[file_name] = true ;
}
}
}
}
bool CommentSaver::hasTrickHeader( std::string file_name ) {
std::string th_str = getTrickHeaderComment(file_name) ;
return (! th_str.empty()) ;
}
bool CommentSaver::hasICGNo( std::string file_name ) {
if ( icg_no_found.find(file_name) == icg_no_found.end() ) {
getICGField(file_name) ;
}
return icg_no_found[file_name] ;
}
bool CommentSaver::hasICGNoComment( std::string file_name ) {
if ( icg_no_comment_found.find(file_name) == icg_no_comment_found.end() ) {
getICGField(file_name) ;
}
return icg_no_comment_found[file_name] ;
}
std::set< std::string > CommentSaver::getIgnoreTypes( std::string file_name ) {
std::set< std::string > ignore_types ;
std::string th_str = getTrickHeaderComment(file_name) ;
if ( ! th_str.empty() ) {
int ret ;
regex_t reg_expr ;
regmatch_t pmatch[10] ;
//std::cout << "here in getIgnoreTypes\n" << th_str << std::endl ;
size_t start = 0 ;
start = th_str.find( "trick_exclude_typename") ;
while ( start != std::string::npos ) {
start += strlen("trick_exclude_typename") ;
std::string temp_str = th_str.substr(start) ;
memset(pmatch , 0 , sizeof(pmatch)) ;
ret = regcomp( &reg_expr , "^\\s*\\{\\s*(\\S+)\\s*\\}" , REG_EXTENDED ) ;
ret = regexec( &reg_expr , temp_str.c_str() , 10 , pmatch , 0 ) ;
regfree(&reg_expr) ;
if ( ret == 0 ) {
std::string item = temp_str.substr(pmatch[1].rm_so, pmatch[1].rm_eo) ;
// regular expression leaving trailing space and brace. Why?
item.erase(item.find_first_of(" \t}")) ;
//std::cout << "icg_ignore_types " << item << std::endl ;
ignore_types.insert(item) ;
}
start = th_str.find( "trick_exclude_typename", start ) ;
}
std::transform(th_str.begin(), th_str.end(), th_str.begin(), ::toupper) ;
memset(pmatch , 0 , sizeof(pmatch)) ;
/* POSIX regular expressions are always greedy, making our job harder.
We have to use several regular expressions to get the types. This was
so much easier in perl! */
/* find the start of the ICG_IGNORE_TYPES field */
ret = regcomp( &reg_expr , "(ICG[ _]IGNORE[ _]TYPE(S)?:)" , REG_EXTENDED | REG_ICASE ) ;
ret = regexec( &reg_expr , th_str.c_str() , 10 , pmatch , 0 ) ;
regfree(&reg_expr) ;
if ( ret != 0 ) {
return std::set< std::string >() ;
}
th_str = th_str.substr(pmatch[1].rm_eo) ;
/* find the end of the ICG_IGNORE_TYPES field */
memset(pmatch , 0 , sizeof(pmatch)) ;
ret = regcomp( &reg_expr , "(\\)\\s*\\))" , REG_EXTENDED ) ;
ret = regexec( &reg_expr , th_str.c_str() , 10 , pmatch , 0 ) ;
regfree(&reg_expr) ;
if ( ret != 0 ) {
return std::set< std::string >() ;
}
th_str = th_str.substr(0 , pmatch[1].rm_so) ;
std::replace( th_str.begin(), th_str.end(), '(', ' ');
std::replace( th_str.begin(), th_str.end(), ')', ' ');
std::replace( th_str.begin(), th_str.end(), '\n', ' ');
std::stringstream ss(th_str);
std::string item;
while (std::getline(ss, item, ' ')) {
if ( ! item.empty() ) {
//std::cout << "icg_ignore_types " << item << std::endl ;
ignore_types.insert(item) ;
}
}
}
return ignore_types ;
}