Clang Rewrite: Locate top of a call expression - clang

I am working on some clang rewrite in source. I want to insert one line before a statement. Like if I have a call from inside an if statement like following:
if (cmp(a,b) > 0 && cmp(c,d) < 0){
//do something
}
I want to rewrite a comment before that if statement, like following:
//there are call inside
if (cmp(a,b) > 0 && cmp(c,d) < 0){
//do something
}
What I could do till now is, I could detect the call with VisitCallExpr(). But how could I find out the location before that if statement to write the comment.
N.B. The if statement here could be for too, like following:
for (int a = 0; a < range(s); a++){
//do something
}
Can anyone help me to find out a way to do this.

I have found a way to do this, although it's not a generalized way to do it. I have opened another question regarding that problem. But, if we consider only the specified situation here like following:
// add something here
if (cmp(a,b)){
//do something
}
We could do with a simple AST matcher:
Matcher.addMatcher(ifStmt(hasCondition(callExpr()))
.bind("call_from_if"),&handleIFCALL);
and handler define should be like:
class IFCALL : public MatchFinder::MatchCallback {
public:
IFCALL(Rewriter &Rewrite) : Rewrite(Rewrite) {}
virtual void run(const MatchFinder::MatchResult &Result) {
const IfStmt *statement =
Result.Nodes.getNodeAs<clang::IfStmt>("call_from_if");
SourceLocation ST = statement->getLocStart();
std::stringstream SSBefore;
SSBefore << "\n \\\\ if statement have call inside \n";
Rewrite.InsertText(ST, SSBefore.str(), true, true);
}
}
private:
Rewriter &Rewrite;
};
This link help me find this solution:
https://jonasdevlieghere.com/understanding-the-clang-ast/
The link to new issue is following:
Clang IfStmt with shortcut binary operator in condition

Related

Is it possible to 'assert' a type using .where()?

I have a list<Components> components; which is sub-class of Bonus, hence Bonus are Components too.
The .toRect() method is defined in the Bonus class but not in the Components class.
I'm making sure I'm only calling .toRect() in Bonus objects, so there should be no problem, but Dart is keeping me from running the code with the following error:
The method 'toRect' isn't defined for the type 'Component'.
Is there a way to go around this problem without the need to define .toRect() on the Components Class?
void checkForCollision() {
controller.components.where((c) => c is Bonus).forEach((bonus) {
if (this.toRect().contains(bonus.toRect().topLeft) ||
this.toRect().contains(bonus.toRect().topCenter) ||
this.toRect().contains(bonus.toRect().topRight)) {
this.remove = true;
}
});
}
Could do:
.forEach((bonus) {
Bonus bonus = bonus;
.....
or
(controller.components.where((c) => c is Bonus) as List<Bonus>).forEach((bonus) {
Use whereType to filter on types. It's like where that just checks for a type, but it also ensures that the resulting iterable has that element type.
controller.components.whereType<Bonus>().forEach((bonus) {
... bonus.toRect ...
});
The Dart style guide recommends not using a function literal with forEach, use a for-loop instead:
for (var bonus in controller.components.whereType<Bonus>()) {
... bonus.toRect ...
}
If you are doing that anyway, you can also just do:
for (var component in controller.compenents) {
if (component is Bonus) {
.. component.toRect ...
}
}
The type promotion from the is check will ensure that you can call toRect.
This very directly specifies what's going on, without creating unnecessary intermediate iterables.

How do functions with multiple parameters of the same name work?

I've been looking through the code for a Flash game (link). However, I'm having trouble understanding how some of these functions work, especially because some of them have function definitions that I would think to fail to get past the compiler.
The following is some code from TodCommon.as that appears to conflict with itself (or at the very least uses bad naming conventions).
private static var gFlashingColor:Color = new Color();
final public static function ClampFloat(ClampInt:Number, ClampInt:Number, ClampInt:Number) : Number
{
if(ClampInt <= ClampInt)
{
return ClampInt;
}
if(ClampInt >= ClampInt)
{
return ClampInt;
}
return ClampInt;
}
final public static function ClampInt(gFlashingColor:int, gFlashingColor:int, gFlashingColor:int) : int
{
if(gFlashingColor <= gFlashingColor)
{
return gFlashingColor;
}
if(gFlashingColor >= gFlashingColor)
{
return gFlashingColor;
}
return gFlashingColor;
}
Also in the code is the weirdest syntax for a for-each loop that I've ever seen (this example also features a package name as a parameter name)
public function CountPlantByType(com.popcap.flash.framework.resources.fonts:int) : int
{
var _loc_3:CPlant = null;
var _loc_2:int = 0;
var _loc_4:int = 0;
var _loc_5:* = this.mPlants;
while(<to complete>)
{
_loc_3 = __nextvalue;
if(_loc_3.mSeedType != com.popcap.flash.framework.resources.fonts)
{
break;
}
_loc_2++;
}
return _loc_2;
}
Those are just a few examples of things that I think look super weird and am having trouble understanding. But these functions all work and are used extensively throughout the code. Can someone explain how the ClampFloat and ClampInt functions work, or why it's legal to use a package name as a parameter? Thanks
Resolved. Turns out the program I used to extract these files from the SWF also corrupted them in the process. Using JPEXS Free Flash Decompiler instead of ActionScriptExtractor fixed the code syntax.

Dart: List remove not removing Object

The code is on DartPad if you need a complete example (see the while loop towards the end.)
I have a loop,
Place place = places[0];
while (places.isNotEmpty) {
// Get a list of places within distance (we can travel to)
List reachables = place.getReachables();
// Get the closest reachable place
Place closest = place.getClosest(reachables);
// Remove the current place (ultimately should terminate the loop)
places.remove(place);
// Iterate
place = closest;
}
But it's not removing place on the second-to-last line. i.e., the length of the places list remains the same, making it an infinite loop. What's wrong?
This could be because the object in the list has a different hashCode from the object you are trying to remove.
Try using this code instead, to find the correct object by comparing the objects properties, before removing it:
var item = list.firstWhere((x) => x.property1== myObj.property1 && x.property2== myObj.property2, orElse: () => null);
list.remove(item);
Another option is to override the == operator and hashCode in your class.
class Class1 {
#override
bool operator==(other) {
if(other is! Class1) {
return false;
}
return property1 == (other as Class1).property1;
}
int _hashCode;
#override
int get hashCode {
if(_hashCode == null) {
_hashCode = property1.hashCode
}
return _hashCode;
}
}
I have faced the very same issue. Unfortunately I haven't found the root cause, but in the same situation I replaced
places.remove[place]
with
places.removeWhere(p => p.hachCode == place.hashCode)
as a workaround. One more approach was helpful too:
// Get the place from your set:
final place = places.first;
// Replace the place in the set:
places.add(place);
// Remove the place from the set:
places.remove(place);
Most likely place is not in the list for some reason. It's hard to debug without knowing the exact data used, the problem doesn't reproduce with the three-place sample you have in the linked DartPad.
Try figuring out which element is causing the problem. For example you can
try adding an if (!places.contains(place)) print("!!! $place not in $places"); before the remove, or something similar that detects the state when the problem occurs.
This way you can remove object from dynamic list
List data = [
{
"name":"stack"
},
{
"name":"overflow"
}
];
data.removeWhere((item) => item["name"]=="stack");
print(data);
Output
[{name: overflow}]
Use the plugin Equatable
class Place extends Equatable {
...
}
https://pub.dev/packages/equatable
I was having the same issue. I did something like this using removeWhere.
myList.removeWhere((item) => item.id == yourItemId.id)

propertyMissing doesn't work in Criteria?

So I've got a couple of classes with the following relationship:
class Foo {
Bar bar
/* ... other fields ... */
}
class Bar {
String name
}
In class Foo I've got a couple of named queries:
static namedQueries = {
userFoos { user ->
/* ... get Foos for this user ... */
}
limitFoos { colname, dir ->
order(colname, dir)
}
...which I can then chain together in a controller:
def foos = Foo.userFoos(currentUser).limit(colname, dir)
Pretty straightforward so far. The problem is when I try to sort on bar; I get the error:
could not resolve property: bar.name of: package.Foo.
Now, I also got this error when the queries were Criteria that were declared in the controller. So, I went and wrote a propertyMissing handler for Foo:
def propertyMissing(String name) {
if (name.contains(".")) {
def (String propertyname, String subproperty) = name.tokenize(".")
if (this.hasProperty(propertyname) && this."$propertyname".hasProperty(subproperty)) {
return this."$propertyname"."$subproperty"
}
}
}
I don't know if this is really the best way to do it, but it did work! However, now that I've moved the query into the class as a named query, propertyMissing doesn't appear to work anymore! Is this use not supported, or am I just missing something here?
EDIT
So I tried moving the Criteria back into the controller and sure enough, the sub-property sort did not work there either! So I guess Criteria just don't support propertyMissing at all :/
To answer dmahapatro's question, I am using jQuery DataTables to present the information. Clicking on a column header does an AJAX call to a controller action with parameters to indicate which column to sort on and in which direction. Once I determine the column name, I call the named queries like so:
def foosFilteredLimited = params.sSearch ?
Foo.userFoos(currentUser).filterFoos(params.sSearch).limitFoos(offset, max, colName, sortDir).list()
: Foo.userFoos(currentUser).limitFoos(offset, max, colName, sortDir).list()
(filterFoos takes a search string and narrows the results of userFoos.)
Try modifying limitFoos namedQuery as below and it should work. There is a caveat to it though. We cannot use bar.baz.name if required. ;)
limitFoos { column, ord ->
def colStrs = column.tokenize(/./).toList()
if( colStrs?.size() > 1 ) {
"${colStrs[0]}" {
order( "${colStrs[1]}", ord )
}
} else {
order(column, ord)
}
}

Are parsers generated by FSYacc thread safe?

If I generate a parser using FSYacc will it be thread safe?
The only reason I ask is because the functions
Parsing.rhs_start_pos and Parsing.symbol_end_pos
don't appear to have any state passed into them, which would lead me to assume that they are getting the current NonTerminal/Symbols from a shared location, is this correct?
After reflecting the code I see that they are getting the postion from a static property
internal static IParseState parse_information
{
get
{
return parse_information;
}
set
{
parse_information = value;
}
}
Is this correct? If so what can I do about it?
Edit: I also see a static method called set_parse_state
public static void set_parse_state(IParseState x)
{
parse_information = x;
}
But that still wont solve my problem...
I really don't like to answer my own question, however since this could save someone else a world of grief someday I will.
It turns out that the functions provided in the parsing module are NOT thread safe.
What you can do however is access the parseState "variable", which is of type IParseState, in your nonterminal action.
For example (rough but work with me):
If you have a NonTerminal like
%token<string> NAME
%%
Person:
NAME NAME { $1 (* action *) }
The code that gets generated is:
(fun (parseState : Microsoft.FSharp.Text.Parsing.IParseState) ->
let _1 = (let data = parseState.GetInput(1) in
(Microsoft.FSharp.Core.Operators.unbox data : string)
) in
Microsoft.FSharp.Core.Operators.box((_1) : 'Person)
);
So you can interact with that parseState object in the same fashion.
%token<string> NAME
%%
Person:
NAME NAME { parseState.DoStuff(); }
The rhs_start_pos method basically does this:
let startPos,endPos = parseState.InputRange(n)
and the symbol_end_pos does this:
let startSymb,endSymb = parseState.ResultRange
I hope this helps

Resources