Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Лабораторная работа №3. Утюгов Денис. 381906-2 #50

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Sindeguru
Copy link

No description provided.


void run(const MatchFinder::MatchResult &Result) override {
// Your code goes here

const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>("cast");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if CastExpr is a null pointer? How to protect the program from crashing in such cases?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Как сказано во втором вопросе, это приводит к сбоям. Тогда необходимо добавить условие, предотвращающее такую ситуацию:

if (CastExpr == nullptr)
  return;

// Your code goes here

const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>("cast");
auto newRange = CharSourceRange::getCharRange(CastExpr->getLParenLoc(), CastExpr->getSubExprAsWritten()->getBeginLoc());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please describe the difference between getSubExprAsWritten()->getBeginLoc() and getRParenLoc().getLocWithOffset(1).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getSubExprAsWritten()->getBeginLoc() указывает на начало названия переменной, а getRParenLoc().getLocWithOffset(1) указывает символы после закрывающей скобки типа.

Рассмотрим такой пример:

int main() {
    float foo;
    int i = (int)      foo ;
    return 0;
}

В случае с getRParenLoc().getLocWithOffset(1) все, что было после закрывающей скобки до точки с запятой :

int main() {
    float foo;
    int i = static_cast<int>(      foo) ;
    return 0;
}

Но, используя getSubExprAsWritten()->getBeginLoc() мы получаем просто название:

int main() {
    float foo;
    int i = static_cast<int>(foo) ;
    return 0;
}

Поэтому использование getSubExprAsWritten()->getBeginLoc() является верным решением.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry but I don't understand the explanation:
В случае с getRParenLoc().getLocWithOffset(1) все, что было после закрывающей скобки до точки с запятой :
Но, используя getSubExprAsWritten()->getBeginLoc() мы получаем просто название:.

Copy link
Author

@Sindeguru Sindeguru May 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это пояснения к примерам. Первый пример кода - то, что подается.
В случае getRParenLoc().getLocWithOffset(1) сохранились пробелы, так как "захват" шел с закрывающей скобки, а в случае с getSubExprAsWritten()->getBeginLoc() - пробелов нет и мы получаем название переменной, так как "захват" шел с первого символа названия переменной.

auto newRange = CharSourceRange::getCharRange(CastExpr->getLParenLoc(), CastExpr->getSubExprAsWritten()->getBeginLoc());
auto &sManager = *Result.SourceManager;

auto sText = Lexer::getSourceText(CharSourceRange::getTokenRange(CastExpr->getLParenLoc().getLocWithOffset(1),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please describe the difference between the use of getCharRange() and getTokenRange() with examples.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will be the deduced type of the sText variable?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getCharRange() возвращает range символов до последнего символа включительно, а getTokenRange() возвращает range токенов до начала последнего токена.

  auto charRange = Lexer::getAsCharRange(
      CharSourceRange::getCharRange(node->getLParenLoc().getLocWithOffset(1),
      node->getRParenLoc().getLocWithOffset(-2)),
      SM, Result.Context->getLangOpts());
  
  auto tokenRange = Lexer::getAsCharRange(
      CharSourceRange::getTokenRange(node->getLParenLoc().getLocWithOffset(1),
      node->getRParenLoc().getLocWithOffset(-2)),
      SM, Result.Context->getLangOpts());
  
  llvm::outs() << "\n char range start: " << charRange.getBegin().printToString(SM) << ",\n char range end: " << charRange.getEnd().printToString(SM) << "\n";
  llvm::outs() << "\n token range start: " << tokenRange.getBegin().printToString(SM) << ",\n token range
 end: " << tokenRange.getEnd().printToString(SM) << "\n";

Вывод:

   char range start: /UNN-C-Style-Checker/test/test.cpp:3:14,
   char range end: /UNN-C-Style-Checker/test/test.cpp:3:15
  
   token range start: /UNN-C-Style-Checker/test/test.cpp
:3:14,
   token range end: /UNN-C-Style-Checker/test/test.cpp:3:17

Для примера:

 int main() {
     float foo;
     int i = (int)     foo ;
     return 0;
 }

sText - llvm::StringRef

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getCharRange() returns range specifying the starting/ending character by the specified locations.
getTokenRange() returns range specifying the start of the range and the start of the last token of the range.

auto sText = Lexer::getSourceText(CharSourceRange::getTokenRange(CastExpr->getLParenLoc().getLocWithOffset(1),
CastExpr->getRParenLoc().getLocWithOffset(-1)), sManager, LangOptions());

const auto *mesneExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please describe why you are using here getSubExprAsWritten() and IgnoreImpCasts().
What would be the difference with the use of getSubExprAsWritten()->IgnoreImpCasts(), getSubExpr()->IgnoreImpCasts() and getSubExprAsWritten()?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getSubExprAsWritten() получает подвыражение приведения в том виде, в каком оно было записано в исходном коде, просматривая любые неявные приведения или другие промежуточные узлы, введенные семантическим анализом. Затем используется IgnoreImpCasts() для того, чтобы игнорировать любые неявные приведения типов, которые могут окружать это выражение.
У нас есть test.cpp. Запуская код из файла, можно заметить, что не будет иметь значения, будем ли мы использовать getSubExprAsWritten() с/без IgnoreImpCasts(). getSubExprAsWritten()->IgnoreImpCasts(), так как getSubExpr()->IgnoreImpCasts() и getSubExprAsWritten() дадут нам один и тот же результат.
Чтобы продемонстрировать это более наглядно, давайте запустим следующее:

llvm::outs() << "getSubExprAsWritten()->IgnoreImpCasts(): " << castNode->getSubExprAsWritten()->IgnoreImpCasts()->getStmtClassName();
llvm::outs() << "getSubExpr()->ignoreImpCasts(): " << castNode->getSubExpr()->IgnoreImpCasts()->getStmtClassName();
llvm::outs() << "getSubExprAsWritten(): " << castNode->getSubExprAsWritten()->getStmtClassName();

Получаем такой результат. На выходе будет ImplicitCastExpr, так как getSubExpr() извлекает первое подвыражение приведения.:

getSubExprAsWritten()->IgnoreImpCasts(): DeclRefExpr
getSubExpr()->ignoreImpCasts(): DeclRefExpr
getSubExprAsWritten(): DeclRefExpr

@ElizJogar
Copy link
Owner

  • How to prevent parentheses from being added if they are already present in the (int)(f) code?
  • How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?
  • How to prevent changing the C style cast code in macros?

Please provide code examples.

@Sindeguru
Copy link
Author

Sindeguru commented May 28, 2022

How to prevent parentheses from being added if they are already present in the (int)(f) code?

Для предотвращения возникновения нежеланных скобок можно использовать в нашем исходном выражении isa<ParenExpr> для проверки того, заключено ли оно в скобки:

if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    newText.append("(");
const auto endLoc = Lexer::getLocForEndOfToken(newExpr->getEndLoc(), 0, sManager, LangOptions());
if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    _rewriter.InsertText(endLoc, ")");

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?

Для ответа на второй вопроса мы можем поместить переменную в выражение (void), чтобы компилятор понимал, что она используется.
Пример с StackOverflow:

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}

или

if (CastExpr->getCastKind() == CK_ToVoid) 
    return;

How to prevent changing the C style cast code in macros?

Для предотвращения изменения кода в макросах мы добавляем проверку:

if (CastExpr->getExprLoc().isMacroID()) 
    return;

@ElizJogar
Copy link
Owner

How to prevent parentheses from being added if they are already present in the (int)(f) code?

Для предотвращения возникновения нежеланных скобок можно использовать в нашем исходном выражении isa<ParenExpr> для проверки того, заключено ли оно в скобки:

if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    newText.append("(");
const auto endLoc = Lexer::getLocForEndOfToken(newExpr->getEndLoc(), 0, sManager, LangOptions());
if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    _rewriter.InsertText(endLoc, ")");

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?

Для ответа на второй вопроса мы можем поместить переменную в выражение (void), чтобы компилятор понимал, что она используется. Пример с StackOverflow:

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}

или

if (CastExpr->getCastKind() == CK_ToVoid) 
    return;

How to prevent changing the C style cast code in macros?

Для предотвращения изменения кода в макросах мы добавляем проверку:

if (CastExpr->getExprLoc().isMacroID()) 
    return;

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?
From your description, I could not understand what exactly you will use in your solution to prevent changing the C-style cast for unused variables.

@Sindeguru
Copy link
Author

Sindeguru commented May 29, 2022

How to prevent parentheses from being added if they are already present in the (int)(f) code?

Для предотвращения возникновения нежеланных скобок можно использовать в нашем исходном выражении isa<ParenExpr> для проверки того, заключено ли оно в скобки:

if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    newText.append("(");
const auto endLoc = Lexer::getLocForEndOfToken(newExpr->getEndLoc(), 0, sManager, LangOptions());
if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    _rewriter.InsertText(endLoc, ")");

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?

Для ответа на второй вопроса мы можем поместить переменную в выражение (void), чтобы компилятор понимал, что она используется. Пример с StackOverflow:

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}

или

if (CastExpr->getCastKind() == CK_ToVoid) 
    return;

How to prevent changing the C style cast code in macros?

Для предотвращения изменения кода в макросах мы добавляем проверку:

if (CastExpr->getExprLoc().isMacroID()) 
    return;

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?
From your description, I could not understand what exactly you will use in your solution to prevent changing the C-style cast for unused variables.

Для подавления таких предупреждений часто помещают переменную в выражение (void), т.е. (void)var;
Если посмотреть на второй пример (который после "или"), то там, для избегания появления предупреждения о неиспользуемых переменных используется метод CastExpr->getCastKind(). И если в итоге он возвращает CK_ToVoid, то вызывается return. По идее, этого достаточно...

@ElizJogar
Copy link
Owner

How to prevent parentheses from being added if they are already present in the (int)(f) code?

Для предотвращения возникновения нежеланных скобок можно использовать в нашем исходном выражении isa<ParenExpr> для проверки того, заключено ли оно в скобки:

if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    newText.append("(");
const auto endLoc = Lexer::getLocForEndOfToken(newExpr->getEndLoc(), 0, sManager, LangOptions());
if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    _rewriter.InsertText(endLoc, ")");

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?

Для ответа на второй вопроса мы можем поместить переменную в выражение (void), чтобы компилятор понимал, что она используется. Пример с StackOverflow:

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}

или

if (CastExpr->getCastKind() == CK_ToVoid) 
    return;

How to prevent changing the C style cast code in macros?

Для предотвращения изменения кода в макросах мы добавляем проверку:

if (CastExpr->getExprLoc().isMacroID()) 
    return;

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?
From your description, I could not understand what exactly you will use in your solution to prevent changing the C-style cast for unused variables.

Для подавления таких предупреждений часто помещают переменную в выражение (void), т.е. (void)var; Если посмотреть на второй пример (который после "или"), то там, для избегания появления предупреждения о неиспользуемых переменных используется метод CastExpr->getCastKind(). И если в итоге он возвращает CK_ToVoid, то вызывается return. По идее, этого достаточно...

Если посмотреть на второй пример (который после "или"), то там, для избегания появления предупреждения о неиспользуемых переменных используется методCastExpr->getCastKind().
This suggestion is incorrect.

@Sindeguru
Copy link
Author

Sindeguru commented May 29, 2022

How to prevent parentheses from being added if they are already present in the (int)(f) code?

Для предотвращения возникновения нежеланных скобок можно использовать в нашем исходном выражении isa<ParenExpr> для проверки того, заключено ли оно в скобки:

if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    newText.append("(");
const auto endLoc = Lexer::getLocForEndOfToken(newExpr->getEndLoc(), 0, sManager, LangOptions());
if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    _rewriter.InsertText(endLoc, ")");

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?

Для ответа на второй вопроса мы можем поместить переменную в выражение (void), чтобы компилятор понимал, что она используется. Пример с StackOverflow:

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}

или

if (CastExpr->getCastKind() == CK_ToVoid) 
    return;

How to prevent changing the C style cast code in macros?

Для предотвращения изменения кода в макросах мы добавляем проверку:

if (CastExpr->getExprLoc().isMacroID()) 
    return;

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?
From your description, I could not understand what exactly you will use in your solution to prevent changing the C-style cast for unused variables.

Для подавления таких предупреждений часто помещают переменную в выражение (void), т.е. (void)var; Если посмотреть на второй пример (который после "или"), то там, для избегания появления предупреждения о неиспользуемых переменных используется метод CastExpr->getCastKind(). И если в итоге он возвращает CK_ToVoid, то вызывается return. По идее, этого достаточно...

Если посмотреть на второй пример (который после "или"), то там, для избегания появления предупреждения о неиспользуемых переменных используется методCastExpr->getCastKind(). This suggestion is incorrect.

Я имел в виду использование метода в условии, а не сам метод. Сам по себе метод CastExpr->getCastKind() вызывает тип приведения. И делается проверка, равно ли оно CK_ToVoid.

@ElizJogar
Copy link
Owner

How to prevent parentheses from being added if they are already present in the (int)(f) code?

Для предотвращения возникновения нежеланных скобок можно использовать в нашем исходном выражении isa<ParenExpr> для проверки того, заключено ли оно в скобки:

if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    newText.append("(");
const auto endLoc = Lexer::getLocForEndOfToken(newExpr->getEndLoc(), 0, sManager, LangOptions());
if (!isa<ParenExpr>(CastExpr->getSubExprAsWritten()->IgnoreImpCasts())) 
    _rewriter.InsertText(endLoc, ")");

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?

Для ответа на второй вопроса мы можем поместить переменную в выражение (void), чтобы компилятор понимал, что она используется. Пример с StackOverflow:

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}

или

if (CastExpr->getCastKind() == CK_ToVoid) 
    return;

How to prevent changing the C style cast code in macros?

Для предотвращения изменения кода в макросах мы добавляем проверку:

if (CastExpr->getExprLoc().isMacroID()) 
    return;

How to prevent changing the C style cast code for a special case - when we want to suppress warnings about unused variables?
From your description, I could not understand what exactly you will use in your solution to prevent changing the C-style cast for unused variables.

Для подавления таких предупреждений часто помещают переменную в выражение (void), т.е. (void)var; Если посмотреть на второй пример (который после "или"), то там, для избегания появления предупреждения о неиспользуемых переменных используется метод CastExpr->getCastKind(). И если в итоге он возвращает CK_ToVoid, то вызывается return. По идее, этого достаточно...

Если посмотреть на второй пример (который после "или"), то там, для избегания появления предупреждения о неиспользуемых переменных используется методCastExpr->getCastKind(). This suggestion is incorrect.

Я имел в виду использование метода в условии, а не сам метод. Сам по себе метод CastExpr->getCastKind() вызывает тип приведения. И делается проверка, равно ли оно CK_ToVoid.

I still don't understand what you want to use in your solution to prevent changing a C style cast to a C++ style cast for cases like this. Please update the code.

@Sindeguru
Copy link
Author

Добавил

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants