You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 11 години
преди 11 години
преди 16 години
преди 15 години
преди 13 години
преди 6 години
преди 15 години
преди 14 години
преди 13 години
преди 18 години
преди 13 години
преди 16 години
преди 13 години
преди 16 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 16 години
преди 14 години
преди 14 години
преди 14 години
преди 15 години
преди 16 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 6 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 18 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 18 години
преди 15 години
преди 18 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 18 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 18 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 16 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 16 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 16 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 16 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 6 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 6 години
преди 15 години
преди 6 години
преди 15 години
преди 6 години
преди 15 години
преди 6 години
преди 15 години
преди 6 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 16 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 6 години
преди 16 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 16 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 12 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 13 години
преди 15 години
преди 13 години
преди 15 години
преди 14 години
преди 15 години
преди 18 години
преди 13 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 15 години
преди 15 години
преди 16 години
преди 15 години
преди 14 години
преди 15 години
преди 16 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 13 години
преди 14 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 14 години
преди 16 години
преди 14 години
преди 14 години
преди 6 години
преди 14 години
преди 14 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 16 години
преди 15 години
преди 15 години
преди 15 години
преди 16 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 16 години
преди 13 години
преди 12 години
преди 13 години
преди 13 години
преди 14 години
преди 14 години
преди 16 години
преди 15 години
преди 15 години
преди 13 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 14 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 6 години
преди 14 години
преди 15 години
преди 6 години
преди 15 години
преди 15 години
преди 18 години
преди 18 години
преди 15 години
преди 15 години
преди 15 години
преди 15 години
преди 14 години
преди 15 години
преди 6 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 13 години
преди 6 години
преди 13 години
преди 10 години
преди 11 години
преди 13 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v 2.0
  6. * which accompanies this distribution and is available at
  7. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * Andy Clement overhauled
  12. * ******************************************************************/
  13. package org.aspectj.ajdt.internal.core.builder;
  14. import java.io.DataOutputStream;
  15. import java.io.File;
  16. import java.io.FileOutputStream;
  17. import java.io.FilenameFilter;
  18. import java.io.IOException;
  19. import java.lang.ref.ReferenceQueue;
  20. import java.lang.ref.SoftReference;
  21. import java.util.AbstractMap;
  22. import java.util.ArrayList;
  23. import java.util.Collection;
  24. import java.util.Collections;
  25. import java.util.HashMap;
  26. import java.util.HashSet;
  27. import java.util.Hashtable;
  28. import java.util.Iterator;
  29. import java.util.LinkedList;
  30. import java.util.List;
  31. import java.util.Map;
  32. import java.util.Set;
  33. import org.aspectj.ajdt.internal.compiler.CompilationResultDestinationManager;
  34. import org.aspectj.ajdt.internal.compiler.InterimCompilationResult;
  35. import org.aspectj.ajdt.internal.core.builder.AjBuildConfig.BinarySourceFile;
  36. import org.aspectj.apache.bcel.classfile.ClassParser;
  37. import org.aspectj.asm.AsmManager;
  38. import org.aspectj.bridge.IMessage;
  39. import org.aspectj.bridge.Message;
  40. import org.aspectj.bridge.SourceLocation;
  41. import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
  42. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  43. import org.aspectj.org.eclipse.jdt.internal.compiler.batch.FileSystem;
  44. import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
  45. import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
  46. import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
  47. import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryField;
  48. import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
  49. import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
  50. import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryType;
  51. import org.aspectj.org.eclipse.jdt.internal.compiler.env.INameEnvironment;
  52. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
  53. import org.aspectj.org.eclipse.jdt.internal.core.builder.ReferenceCollection;
  54. import org.aspectj.org.eclipse.jdt.internal.core.builder.StringSet;
  55. import org.aspectj.util.FileUtil;
  56. import org.aspectj.weaver.BCException;
  57. import org.aspectj.weaver.CompressingDataOutputStream;
  58. import org.aspectj.weaver.ReferenceType;
  59. import org.aspectj.weaver.ReferenceTypeDelegate;
  60. import org.aspectj.weaver.ResolvedType;
  61. import org.aspectj.weaver.bcel.BcelWeaver;
  62. import org.aspectj.weaver.bcel.BcelWorld;
  63. import org.aspectj.weaver.bcel.TypeDelegateResolver;
  64. import org.aspectj.weaver.bcel.UnwovenClassFile;
  65. /**
  66. * Maintains state needed for incremental compilation
  67. */
  68. public class AjState implements CompilerConfigurationChangeFlags, TypeDelegateResolver {
  69. // SECRETAPI configures whether we use state instead of lastModTime - see pr245566
  70. public static boolean CHECK_STATE_FIRST = true;
  71. // SECRETAPI static so beware of multi-threading bugs...
  72. public static IStateListener stateListener = null;
  73. public static boolean FORCE_INCREMENTAL_DURING_TESTING = false;
  74. static int PATHID_CLASSPATH = 0;
  75. static int PATHID_ASPECTPATH = 1;
  76. static int PATHID_INPATH = 2;
  77. private static int CLASS_FILE_NO_CHANGES = 0;
  78. private static int CLASS_FILE_CHANGED_THAT_NEEDS_INCREMENTAL_BUILD = 1;
  79. private static int CLASS_FILE_CHANGED_THAT_NEEDS_FULL_BUILD = 2;
  80. private static final char[][] EMPTY_CHAR_ARRAY = new char[0][];
  81. // now follows non static, but transient state - no need to write out, doesn't need reinitializing
  82. // State recreated for each build:
  83. /**
  84. * When looking at changes on the classpath, this set accumulates files in our state instance that affected by those changes.
  85. * Then if we can do an incremental build - these must be compiled.
  86. */
  87. private final Set<File> affectedFiles = new HashSet<>();
  88. // these are references created on a particular compile run - when looping round in
  89. // addAffectedSourceFiles(), if some have been created then we look at which source files
  90. // touch upon those and get them recompiled.
  91. private StringSet qualifiedStrings = new StringSet(3);
  92. private StringSet simpleStrings = new StringSet(3);
  93. private Set<File> addedFiles;
  94. private Set<File> deletedFiles;
  95. private Set<BinarySourceFile> addedBinaryFiles;
  96. private Set<BinarySourceFile> deletedBinaryFiles;
  97. // For a particular build run, this set records the changes to classesFromName
  98. public final Set<String> deltaAddedClasses = new HashSet<>();
  99. // now follows non static, but transient state - no need to write out, DOES need reinitializing when read AjState instance
  100. // reloaded
  101. private final AjBuildManager buildManager;
  102. private INameEnvironment nameEnvironment;
  103. private FileSystem fileSystem;
  104. // now follows normal state that must be written out
  105. private boolean couldBeSubsequentIncrementalBuild = false;
  106. private boolean batchBuildRequiredThisTime = false;
  107. private AjBuildConfig buildConfig;
  108. private long lastSuccessfulFullBuildTime = -1;
  109. private final Hashtable<String, Long> structuralChangesSinceLastFullBuild = new Hashtable<>();
  110. private long lastSuccessfulBuildTime = -1;
  111. private long currentBuildTime = -1;
  112. private AsmManager structureModel;
  113. /**
  114. * For a given source file, records the ClassFiles (which contain a fully qualified name and a file name) that were created when
  115. * the source file was compiled. Populated in noteResult and used in addDependentsOf(File)
  116. */
  117. private final Map<File, List<ClassFile>> fullyQualifiedTypeNamesResultingFromCompilationUnit = new HashMap<>();
  118. /**
  119. * Source files defining aspects Populated in noteResult and used in processDeletedFiles
  120. */
  121. private final Set<File> sourceFilesDefiningAspects = new HashSet<>();
  122. /**
  123. * Populated in noteResult to record the set of types that should be recompiled if the given file is modified or deleted.
  124. * Referred to during addAffectedSourceFiles when calculating incremental compilation set.
  125. */
  126. private final Map<File, ReferenceCollection> references = new HashMap<>();
  127. /**
  128. * Holds UnwovenClassFiles (byte[]s) originating from the given file source. This could be a jar file, a directory, or an
  129. * individual .class file. This is an *expensive* map. It is cleared immediately following a batch build, and the cheaper
  130. * inputClassFilesBySource map is kept for processing of any subsequent incremental builds.
  131. *
  132. * Populated during AjBuildManager.initBcelWorld().
  133. *
  134. * Passed into AjCompiler adapter as the set of binary input files to reweave if the weaver determines a full weave is required.
  135. *
  136. * Cleared during initBcelWorld prior to repopulation.
  137. *
  138. * Used when a file is deleted during incremental compilation to delete all of the class files in the output directory that
  139. * resulted from the weaving of File.
  140. *
  141. * Used during getBinaryFilesToCompile when compiling incrementally to determine which files should be recompiled if a given
  142. * input file has changed.
  143. *
  144. */
  145. private Map<String, List<UnwovenClassFile>> binarySourceFiles = new HashMap<>();
  146. /**
  147. * Initially a duplicate of the information held in binarySourceFiles, with the key difference that the values are ClassFiles
  148. * (type name, File) not UnwovenClassFiles (which also have all the byte code in them). After a batch build, binarySourceFiles
  149. * is cleared, leaving just this much lighter weight map to use in processing subsequent incremental builds.
  150. */
  151. private final Map<String, List<ClassFile>> inputClassFilesBySource = new HashMap<>();
  152. /**
  153. * A list of the .class files created by this state that contain aspects.
  154. */
  155. private final List<String> aspectClassFiles = new ArrayList<>();
  156. /**
  157. * Holds structure information on types as they were at the end of the last build. It would be nice to get rid of this too, but
  158. * can't see an easy way to do that right now.
  159. */
  160. private final Map<String, CompactTypeStructureRepresentation> resolvedTypeStructuresFromLastBuild = new HashMap<>();
  161. /**
  162. * Populated in noteResult to record the set of UnwovenClassFiles (intermediate results) that originated from compilation of the
  163. * class with the given fully-qualified name.
  164. *
  165. * Used in removeAllResultsOfLastBuild to remove .class files from output directory.
  166. *
  167. * Passed into StatefulNameEnvironment during incremental compilation to support findType lookups.
  168. */
  169. private final Map<String, File> classesFromName = new HashMap<>();
  170. /**
  171. * Populated by AjBuildManager to record the aspects with the file name in which they're contained. This is later used when
  172. * writing the outxml file in AjBuildManager. Need to record the file name because want to write an outxml file for each of the
  173. * output directories and in order to ask the OutputLocationManager for the output location for a given aspect we need the file
  174. * in which it is contained.
  175. */
  176. private Map<String, char[]> aspectsFromFileNames;
  177. private Set<File> compiledSourceFiles = new HashSet<>();
  178. private final Map<String, File> resources = new HashMap<>();
  179. SoftHashMap/* <baseDir,SoftHashMap<theFile,className>> */fileToClassNameMap = new SoftHashMap();
  180. private BcelWeaver weaver;
  181. private BcelWorld world;
  182. // --- below here is unsorted state
  183. // ---
  184. public AjState(AjBuildManager buildManager) {
  185. this.buildManager = buildManager;
  186. }
  187. public void setCouldBeSubsequentIncrementalBuild(boolean yesThereCould) {
  188. this.couldBeSubsequentIncrementalBuild = yesThereCould;
  189. }
  190. void successfulCompile(AjBuildConfig config, boolean wasFullBuild) {
  191. buildConfig = config;
  192. lastSuccessfulBuildTime = currentBuildTime;
  193. if (stateListener != null) {
  194. stateListener.buildSuccessful(wasFullBuild);
  195. }
  196. if (wasFullBuild) {
  197. lastSuccessfulFullBuildTime = currentBuildTime;
  198. }
  199. }
  200. /**
  201. * Returns false if a batch build is needed.
  202. */
  203. public boolean prepareForNextBuild(AjBuildConfig newBuildConfig) {
  204. currentBuildTime = System.currentTimeMillis();
  205. if (!maybeIncremental()) {
  206. if (listenerDefined()) {
  207. getListener().recordDecision(
  208. "Preparing for build: not going to be incremental because either not in AJDT or incremental deactivated");
  209. }
  210. return false;
  211. }
  212. if (this.batchBuildRequiredThisTime) {
  213. this.batchBuildRequiredThisTime = false;
  214. if (listenerDefined()) {
  215. getListener().recordDecision(
  216. "Preparing for build: not going to be incremental this time because batch build explicitly forced");
  217. }
  218. return false;
  219. }
  220. if (lastSuccessfulBuildTime == -1 || buildConfig == null) {
  221. structuralChangesSinceLastFullBuild.clear();
  222. if (listenerDefined()) {
  223. getListener().recordDecision(
  224. "Preparing for build: not going to be incremental because no successful previous full build");
  225. }
  226. return false;
  227. }
  228. // we don't support incremental with an outjar yet
  229. if (newBuildConfig.getOutputJar() != null) {
  230. structuralChangesSinceLastFullBuild.clear();
  231. if (listenerDefined()) {
  232. getListener().recordDecision("Preparing for build: not going to be incremental because outjar being used");
  233. }
  234. return false;
  235. }
  236. affectedFiles.clear();
  237. // we can't do an incremental build if one of our paths
  238. // has changed, or a jar on a path has been modified
  239. if (pathChange(buildConfig, newBuildConfig)) {
  240. // last time we built, .class files and resource files from jars on the
  241. // inpath will have been copied to the output directory.
  242. // these all need to be deleted in preparation for the clean build that is
  243. // coming - otherwise a file that has been deleted from an inpath jar
  244. // since the last build will not be deleted from the output directory.
  245. removeAllResultsOfLastBuild();
  246. if (stateListener != null) {
  247. stateListener.pathChangeDetected();
  248. }
  249. structuralChangesSinceLastFullBuild.clear();
  250. if (listenerDefined()) {
  251. getListener()
  252. .recordDecision(
  253. "Preparing for build: not going to be incremental because path change detected (one of classpath/aspectpath/inpath/injars)");
  254. }
  255. return false;
  256. }
  257. if (simpleStrings.elementSize > 20) {
  258. simpleStrings = new StringSet(3);
  259. } else {
  260. simpleStrings.clear();
  261. }
  262. if (qualifiedStrings.elementSize > 20) {
  263. qualifiedStrings = new StringSet(3);
  264. } else {
  265. qualifiedStrings.clear();
  266. }
  267. if ((newBuildConfig.getChanged() & PROJECTSOURCEFILES_CHANGED) == 0) {
  268. addedFiles = Collections.emptySet();
  269. deletedFiles = Collections.emptySet();
  270. } else {
  271. Set<File> oldFiles = new HashSet<>(buildConfig.getFiles());
  272. Set<File> newFiles = new HashSet<>(newBuildConfig.getFiles());
  273. addedFiles = new HashSet<>(newFiles);
  274. addedFiles.removeAll(oldFiles);
  275. deletedFiles = new HashSet<>(oldFiles);
  276. deletedFiles.removeAll(newFiles);
  277. }
  278. Set<BinarySourceFile> oldBinaryFiles = new HashSet<>(buildConfig.getBinaryFiles());
  279. Set<BinarySourceFile> newBinaryFiles = new HashSet<>(newBuildConfig.getBinaryFiles());
  280. addedBinaryFiles = new HashSet<>(newBinaryFiles);
  281. addedBinaryFiles.removeAll(oldBinaryFiles);
  282. deletedBinaryFiles = new HashSet<>(oldBinaryFiles);
  283. deletedBinaryFiles.removeAll(newBinaryFiles);
  284. boolean couldStillBeIncremental = processDeletedFiles(deletedFiles);
  285. if (!couldStillBeIncremental) {
  286. if (listenerDefined()) {
  287. getListener().recordDecision("Preparing for build: not going to be incremental because an aspect was deleted");
  288. }
  289. return false;
  290. }
  291. if (listenerDefined()) {
  292. getListener().recordDecision("Preparing for build: planning to be an incremental build");
  293. }
  294. return true;
  295. }
  296. /**
  297. * Checks if any of the files in the set passed in contains an aspect declaration. If one is found then we start the process of
  298. * batch building, i.e. we remove all the results of the last build, call any registered listener to tell them whats happened
  299. * and return false.
  300. *
  301. * @return false if we discovered an aspect declaration
  302. */
  303. private boolean processDeletedFiles(Set<File> deletedFiles) {
  304. for (File deletedFile : deletedFiles) {
  305. if (this.sourceFilesDefiningAspects.contains(deletedFile)) {
  306. removeAllResultsOfLastBuild();
  307. if (stateListener != null) {
  308. stateListener.detectedAspectDeleted(deletedFile);
  309. }
  310. return false;
  311. }
  312. List<ClassFile> classes = fullyQualifiedTypeNamesResultingFromCompilationUnit.get(deletedFile);
  313. if (classes != null) {
  314. for (ClassFile cf : classes) {
  315. resolvedTypeStructuresFromLastBuild.remove(cf.fullyQualifiedTypeName);
  316. }
  317. }
  318. }
  319. return true;
  320. }
  321. private Collection<File> getModifiedFiles() {
  322. return getModifiedFiles(lastSuccessfulBuildTime);
  323. }
  324. Collection<File> getModifiedFiles(long lastBuildTime) {
  325. Set<File> ret = new HashSet<>();
  326. // Check if the build configuration knows what files have changed...
  327. List<File> modifiedFiles = buildConfig.getModifiedFiles();
  328. if (modifiedFiles == null) {
  329. // do not know, so need to go looking
  330. // not our job to account for new and deleted files
  331. for (File file : buildConfig.getFiles()) {
  332. if (!file.exists()) {
  333. continue;
  334. }
  335. long modTime = file.lastModified();
  336. // System.out.println("check: " + file + " mod " + modTime + " build " + lastBuildTime);
  337. // need to add 1000 since lastModTime is only accurate to a second on some (all?) platforms
  338. if (modTime + 1000 > lastBuildTime) {
  339. ret.add(file);
  340. }
  341. }
  342. } else {
  343. ret.addAll(modifiedFiles);
  344. }
  345. ret.addAll(affectedFiles);
  346. return ret;
  347. }
  348. private Collection<BinarySourceFile> getModifiedBinaryFiles() {
  349. return getModifiedBinaryFiles(lastSuccessfulBuildTime);
  350. }
  351. Collection<BinarySourceFile> getModifiedBinaryFiles(long lastBuildTime) {
  352. List<BinarySourceFile> ret = new ArrayList<>();
  353. // not our job to account for new and deleted files
  354. for (BinarySourceFile bsfile : buildConfig.getBinaryFiles()) {
  355. File file = bsfile.binSrc;
  356. if (!file.exists()) {
  357. continue;
  358. }
  359. long modTime = file.lastModified();
  360. // System.out.println("check: " + file + " mod " + modTime + " build " + lastBuildTime);
  361. // need to add 1000 since lastModTime is only accurate to a second on some (all?) platforms
  362. if (modTime + 1000 >= lastBuildTime) {
  363. ret.add(bsfile);
  364. }
  365. }
  366. return ret;
  367. }
  368. private void recordDecision(String decision) {
  369. getListener().recordDecision(decision);
  370. }
  371. /**
  372. * Analyse .class files in the directory specified, if they have changed since the last successful build then see if we can
  373. * determine which source files in our project depend on the change. If we can then we can still do an incremental build, if we
  374. * can't then we have to do a full build.
  375. *
  376. */
  377. private int classFileChangedInDirSinceLastBuildRequiringFullBuild(File dir, int pathid) {
  378. if (!dir.isDirectory()) {
  379. if (listenerDefined()) {
  380. recordDecision("ClassFileChangeChecking: not a directory so forcing full build: '" + dir.getPath() + "'");
  381. }
  382. return CLASS_FILE_CHANGED_THAT_NEEDS_FULL_BUILD;
  383. }
  384. // Are we managing that output directory?
  385. AjState state = IncrementalStateManager.findStateManagingOutputLocation(dir);
  386. if (listenerDefined()) {
  387. if (state != null) {
  388. recordDecision("ClassFileChangeChecking: found state instance managing output location : " + dir);
  389. } else {
  390. recordDecision("ClassFileChangeChecking: failed to find a state instance managing output location : " + dir + " (could be getting managed by JDT)");
  391. }
  392. }
  393. // pr268827 - this guard will cause us to exit quickly if the state says there really is
  394. // nothing of interest. This will not catch the case where a user modifies the .class files outside of
  395. // eclipse because the state will not be aware of it. But that seems an unlikely scenario and
  396. // we are paying a heavy price to check it
  397. if (state != null && !state.hasAnyStructuralChangesSince(lastSuccessfulBuildTime)) {
  398. if (listenerDefined()) {
  399. getListener().recordDecision("ClassFileChangeChecking: no reported changes in that state");
  400. }
  401. return CLASS_FILE_NO_CHANGES;
  402. }
  403. if (state == null) {
  404. // This may be because the directory is the output path of a Java project upon which we depend
  405. // we need to call back into AJDT to ask about that projects state.
  406. CompilationResultDestinationManager crdm = buildConfig.getCompilationResultDestinationManager();
  407. if (crdm != null) {
  408. int i = crdm.discoverChangesSince(dir, lastSuccessfulBuildTime);
  409. // 0 = dontknow if it has changed
  410. // 1 = definetly not changed at all
  411. // further numbers can determine more granular changes
  412. if (i == 1) {
  413. if (listenerDefined()) {
  414. getListener().recordDecision(
  415. "ClassFileChangeChecking: queried JDT and '" + dir
  416. + "' is apparently unchanged so not performing timestamp check");
  417. }
  418. return CLASS_FILE_NO_CHANGES;
  419. }
  420. }
  421. }
  422. List<File> classFiles = FileUtil.listClassFiles(dir);
  423. for (File classFile : classFiles) {
  424. if (CHECK_STATE_FIRST && state != null) {
  425. // Next section reworked based on bug 270033:
  426. // if it is an aspect we may or may not be in trouble depending on whether (a) we depend on it (b) it is on the
  427. // classpath or the aspectpath
  428. if (state.isAspect(classFile)) {
  429. boolean hasStructuralChanges = state.hasStructuralChangedSince(classFile, lastSuccessfulBuildTime);
  430. if (hasStructuralChanges || isTypeWeReferTo(classFile)) {
  431. if (hasStructuralChanges) {
  432. if (listenerDefined()) {
  433. getListener().recordDecision(
  434. "ClassFileChangeChecking: aspect found that has structurally changed : " + classFile);
  435. }
  436. return CLASS_FILE_CHANGED_THAT_NEEDS_FULL_BUILD;
  437. } else {
  438. // must be 'isTypeWeReferTo()'
  439. if (pathid == PATHID_CLASSPATH) {
  440. if (listenerDefined()) {
  441. getListener().recordDecision(
  442. "ClassFileChangeChecking: aspect found that this project refers to : " + classFile
  443. + " but only referred to via classpath");
  444. }
  445. } else {
  446. if (listenerDefined()) {
  447. getListener().recordDecision(
  448. "ClassFileChangeChecking: aspect found that this project refers to : " + classFile
  449. + " from either inpath/aspectpath, switching to full build");
  450. }
  451. return CLASS_FILE_CHANGED_THAT_NEEDS_FULL_BUILD;
  452. }
  453. }
  454. } else {
  455. // it is an aspect but we don't refer to it:
  456. // - for CLASSPATH I think this is OK, we can continue and try an
  457. // incremental build
  458. // - for ASPECTPATH we don't know what else might be touched in this project
  459. // and must rebuild
  460. if (pathid == PATHID_CLASSPATH) {
  461. if (listenerDefined()) {
  462. getListener()
  463. .recordDecision(
  464. "ClassFileChangeChecking: found aspect on classpath but this project doesn't reference it, continuing to try for incremental build : "
  465. + classFile);
  466. }
  467. } else {
  468. if (listenerDefined()) {
  469. getListener().recordDecision(
  470. "ClassFileChangeChecking: found aspect on aspectpath/inpath - can't determine if this project is affected, must full build: "
  471. + classFile);
  472. }
  473. return CLASS_FILE_CHANGED_THAT_NEEDS_FULL_BUILD;
  474. }
  475. }
  476. }
  477. if (state.hasStructuralChangedSince(classFile, lastSuccessfulBuildTime)) {
  478. if (listenerDefined()) {
  479. getListener().recordDecision("ClassFileChangeChecking: structural change detected in : " + classFile);
  480. }
  481. isTypeWeReferTo(classFile);
  482. }
  483. } else {
  484. long modTime = classFile.lastModified();
  485. if ((modTime + 1000) >= lastSuccessfulBuildTime) {
  486. // so the class on disk has changed since the last successful build for this state object
  487. // BUG? we stop on the first change that leads us to an incremental build, surely we need to continue and look
  488. // at all files incase another change means we need to incremental a bit more stuff?
  489. // To work out if it is a real change we should ask any state
  490. // object managing the output location whether the file has
  491. // structurally changed or not
  492. if (state != null) {
  493. if (state.isAspect(classFile)) {
  494. if (state.hasStructuralChangedSince(classFile, lastSuccessfulBuildTime) || isTypeWeReferTo(classFile)) {
  495. // further improvements possible
  496. if (listenerDefined()) {
  497. getListener().recordDecision(
  498. "ClassFileChangeChecking: aspect found that has structurally changed or that this project depends upon : "
  499. + classFile);
  500. }
  501. return CLASS_FILE_CHANGED_THAT_NEEDS_FULL_BUILD;
  502. } else {
  503. // it is an aspect but we don't refer to it:
  504. // - for CLASSPATH I think this is OK, we can continue and try an
  505. // incremental build
  506. // - for ASPECTPATH we don't know what else might be touched in this project
  507. // and must rebuild
  508. if (pathid == PATHID_CLASSPATH) {
  509. if (listenerDefined()) {
  510. getListener()
  511. .recordDecision(
  512. "ClassFileChangeChecking: found aspect on classpath but this project doesn't reference it, continuing to try for incremental build : "
  513. + classFile);
  514. }
  515. } else {
  516. if (listenerDefined()) {
  517. getListener().recordDecision(
  518. "ClassFileChangeChecking: found aspect on aspectpath/inpath - can't determine if this project is affected, must full build: "
  519. + classFile);
  520. }
  521. return CLASS_FILE_CHANGED_THAT_NEEDS_FULL_BUILD;
  522. }
  523. }
  524. }
  525. if (state.hasStructuralChangedSince(classFile, lastSuccessfulBuildTime)) {
  526. if (listenerDefined()) {
  527. getListener().recordDecision(
  528. "ClassFileChangeChecking: structural change detected in : " + classFile);
  529. }
  530. isTypeWeReferTo(classFile);
  531. } else {
  532. if (listenerDefined()) {
  533. getListener().recordDecision(
  534. "ClassFileChangeChecking: change detected in " + classFile + " but it is not structural");
  535. }
  536. }
  537. } else {
  538. // No state object to ask, so it only matters if we know which type depends on this file
  539. if (isTypeWeReferTo(classFile)) {
  540. return CLASS_FILE_CHANGED_THAT_NEEDS_INCREMENTAL_BUILD;
  541. } else {
  542. return CLASS_FILE_NO_CHANGES;
  543. }
  544. }
  545. }
  546. }
  547. }
  548. return CLASS_FILE_NO_CHANGES;
  549. }
  550. private boolean isAspect(File file) {
  551. return aspectClassFiles.contains(file.getAbsolutePath());
  552. }
  553. @SuppressWarnings("rawtypes")
  554. public static class SoftHashMap extends AbstractMap {
  555. private final Map map;
  556. private final ReferenceQueue rq = new ReferenceQueue();
  557. public SoftHashMap(Map map) {
  558. this.map = map;
  559. }
  560. public SoftHashMap() {
  561. this(new HashMap());
  562. }
  563. public SoftHashMap(Map map, boolean b) {
  564. this(map);
  565. }
  566. class SoftReferenceKnownKey extends SoftReference {
  567. private final Object key;
  568. @SuppressWarnings("unchecked")
  569. SoftReferenceKnownKey(Object k, Object v) {
  570. super(v, rq);
  571. this.key = k;
  572. }
  573. }
  574. private void processQueue() {
  575. SoftReferenceKnownKey sv = null;
  576. while ((sv = (SoftReferenceKnownKey) rq.poll()) != null) {
  577. map.remove(sv.key);
  578. }
  579. }
  580. @Override
  581. public Object get(Object key) {
  582. SoftReferenceKnownKey value = (SoftReferenceKnownKey) map.get(key);
  583. if (value == null) {
  584. return null;
  585. }
  586. if (value.get() == null) {
  587. // it got GC'd
  588. map.remove(value.key);
  589. return null;
  590. } else {
  591. return value.get();
  592. }
  593. }
  594. @Override
  595. public Object put(Object k, Object v) {
  596. processQueue();
  597. return map.put(k, new SoftReferenceKnownKey(k, v));
  598. }
  599. @Override
  600. public Set entrySet() {
  601. return map.entrySet();
  602. }
  603. @Override
  604. public void clear() {
  605. processQueue();
  606. map.clear();
  607. }
  608. @Override
  609. public int size() {
  610. processQueue();
  611. return map.size();
  612. }
  613. @Override
  614. public Object remove(Object k) {
  615. processQueue();
  616. SoftReferenceKnownKey value = (SoftReferenceKnownKey) map.remove(k);
  617. if (value == null) {
  618. return null;
  619. }
  620. if (value.get() != null) {
  621. return value.get();
  622. }
  623. return null;
  624. }
  625. }
  626. /**
  627. * If a class file has changed in a path on our classpath, it may not be for a type that any of our source files care about.
  628. * This method checks if any of our source files have a dependency on the class in question and if not, we don't consider it an
  629. * interesting change.
  630. */
  631. private boolean isTypeWeReferTo(File file) {
  632. String fpath = file.getAbsolutePath();
  633. int finalSeparator = fpath.lastIndexOf(File.separator);
  634. String baseDir = fpath.substring(0, finalSeparator);
  635. String theFile = fpath.substring(finalSeparator + 1);
  636. SoftHashMap classNames = (SoftHashMap) fileToClassNameMap.get(baseDir);
  637. if (classNames == null) {
  638. classNames = new SoftHashMap();
  639. fileToClassNameMap.put(baseDir, classNames);
  640. }
  641. char[] className = (char[]) classNames.get(theFile);
  642. if (className == null) {
  643. // if (listenerDefined())
  644. // getListener().recordDecision("Cache miss, looking up classname for : " + fpath);
  645. ClassFileReader cfr;
  646. try {
  647. cfr = ClassFileReader.read(file);
  648. } catch (ClassFormatException e) {
  649. return true;
  650. } catch (IOException e) {
  651. return true;
  652. }
  653. className = cfr.getName();
  654. classNames.put(theFile, className);
  655. // } else {
  656. // if (listenerDefined())
  657. // getListener().recordDecision("Cache hit, looking up classname for : " + fpath);
  658. }
  659. char[][][] qualifiedNames = null;
  660. char[][] simpleNames = null;
  661. if (CharOperation.indexOf('/', className) != -1) {
  662. qualifiedNames = new char[1][][];
  663. qualifiedNames[0] = CharOperation.splitOn('/', className);
  664. qualifiedNames = ReferenceCollection.internQualifiedNames(qualifiedNames);
  665. } else {
  666. simpleNames = new char[1][];
  667. simpleNames[0] = className;
  668. simpleNames = ReferenceCollection.internSimpleNames(simpleNames, true);
  669. }
  670. int newlyAffectedFiles = 0;
  671. for (Map.Entry<File, ReferenceCollection> entry : references.entrySet()) {
  672. ReferenceCollection refs = entry.getValue();
  673. if (refs != null && refs.includes(qualifiedNames, simpleNames)) {
  674. if (listenerDefined()) {
  675. getListener().recordDecision(
  676. toString() + ": type " + new String(className) + " is depended upon by '" + entry.getKey() + "'");
  677. }
  678. newlyAffectedFiles++;
  679. // possibly the beginnings of addressing the second point in 270033 comment 3
  680. // List/*ClassFile*/ cfs = (List)this.fullyQualifiedTypeNamesResultingFromCompilationUnit.get(entry.getKey());
  681. affectedFiles.add(entry.getKey());
  682. }
  683. }
  684. if (newlyAffectedFiles > 0) {
  685. return true;
  686. }
  687. if (listenerDefined()) {
  688. getListener().recordDecision(toString() + ": type " + new String(className) + " is not depended upon by this state");
  689. }
  690. return false;
  691. }
  692. // /**
  693. // * For a given class file, determine which source file it came from. This will only succeed if the class file is from a source
  694. // * file within this project.
  695. // */
  696. // private File getSourceFileForClassFile(File classfile) {
  697. // Set sourceFiles = fullyQualifiedTypeNamesResultingFromCompilationUnit.keySet();
  698. // for (Iterator sourceFileIterator = sourceFiles.iterator(); sourceFileIterator.hasNext();) {
  699. // File sourceFile = (File) sourceFileIterator.next();
  700. // List/* ClassFile */classesFromSourceFile = (List/* ClassFile */) fullyQualifiedTypeNamesResultingFromCompilationUnit
  701. // .get(sourceFile);
  702. // for (int i = 0; i < classesFromSourceFile.size(); i++) {
  703. // if (((ClassFile) classesFromSourceFile.get(i)).locationOnDisk.equals(classfile))
  704. // return sourceFile;
  705. // }
  706. // }
  707. // return null;
  708. // }
  709. @Override
  710. public String toString() {
  711. StringBuilder sb = new StringBuilder();
  712. // null config means failed build i think as it is only set on successful full build?
  713. sb.append("AjState(").append((buildConfig == null ? "NULLCONFIG" : buildConfig.getConfigFile().toString())).append(")");
  714. return sb.toString();
  715. }
  716. /**
  717. * Determine if a file has changed since a given time, using the local information recorded in the structural changes data
  718. * structure.
  719. *
  720. * @param file the file we are wondering about
  721. * @param lastSuccessfulBuildTime the last build time for the state asking the question
  722. */
  723. private boolean hasStructuralChangedSince(File file, long lastSuccessfulBuildTime) {
  724. // long lastModTime = file.lastModified();
  725. Long l = structuralChangesSinceLastFullBuild.get(file.getAbsolutePath());
  726. long strucModTime = -1;
  727. if (l != null) {
  728. strucModTime = l;
  729. } else {
  730. strucModTime = this.lastSuccessfulFullBuildTime;
  731. }
  732. // we now have:
  733. // 'strucModTime'-> the last time the class was structurally changed
  734. return (strucModTime > lastSuccessfulBuildTime);
  735. }
  736. /**
  737. * Determine if anything has changed since a given time.
  738. */
  739. private boolean hasAnyStructuralChangesSince(long lastSuccessfulBuildTime) {
  740. Set<Map.Entry<String, Long>> entries = structuralChangesSinceLastFullBuild.entrySet();
  741. for (Map.Entry<String, Long> entry : entries) {
  742. Long l = entry.getValue();
  743. if (l != null) {
  744. long lvalue = l;
  745. if (lvalue > lastSuccessfulBuildTime) {
  746. if (listenerDefined()) {
  747. getListener().recordDecision(
  748. "Seems this has changed " + entry.getKey() + "modtime=" + lvalue + " lsbt="
  749. + this.lastSuccessfulFullBuildTime + " incoming check value=" + lastSuccessfulBuildTime);
  750. }
  751. return true;
  752. }
  753. }
  754. }
  755. return (this.lastSuccessfulFullBuildTime > lastSuccessfulBuildTime);
  756. }
  757. /**
  758. * Determine if something has changed on the classpath/inpath/aspectpath and a full build is required rather than an incremental
  759. * one.
  760. *
  761. * @param previousConfig the previous configuration used
  762. * @param newConfig the new configuration being used
  763. * @return true if full build required
  764. */
  765. private boolean pathChange(AjBuildConfig previousConfig, AjBuildConfig newConfig) {
  766. int changes = newConfig.getChanged();
  767. if ((changes & (CLASSPATH_CHANGED | ASPECTPATH_CHANGED | INPATH_CHANGED | OUTPUTDESTINATIONS_CHANGED | INJARS_CHANGED)) != 0) {
  768. List<File> oldOutputLocs = getOutputLocations(previousConfig);
  769. Set<String> alreadyAnalysedPaths = new HashSet<>();
  770. List<String> oldClasspath = previousConfig.getClasspath();
  771. List<String> newClasspath = newConfig.getClasspath();
  772. if (stateListener != null) {
  773. stateListener.aboutToCompareClasspaths(oldClasspath, newClasspath);
  774. }
  775. if (classpathChangedAndNeedsFullBuild(oldClasspath, newClasspath, true, oldOutputLocs, alreadyAnalysedPaths)) {
  776. return true;
  777. }
  778. List<File> oldAspectpath = previousConfig.getAspectpath();
  779. List<File> newAspectpath = newConfig.getAspectpath();
  780. if (changedAndNeedsFullBuild(oldAspectpath, newAspectpath, true, oldOutputLocs, alreadyAnalysedPaths, PATHID_ASPECTPATH)) {
  781. return true;
  782. }
  783. List<File> oldInPath = previousConfig.getInpath();
  784. List<File> newInPath = newConfig.getInpath();
  785. if (changedAndNeedsFullBuild(oldInPath, newInPath, false, oldOutputLocs, alreadyAnalysedPaths, PATHID_INPATH)) {
  786. return true;
  787. }
  788. List<File> oldInJars = previousConfig.getInJars();
  789. List<File> newInJars = newConfig.getInJars();
  790. if (changedAndNeedsFullBuild(oldInJars, newInJars, false, oldOutputLocs, alreadyAnalysedPaths, PATHID_INPATH)) {
  791. return true;
  792. }
  793. } else if (newConfig.getClasspathElementsWithModifiedContents() != null) {
  794. // Although the classpath entries themselves are the same as before, the contents of one of the
  795. // directories on the classpath has changed - rather than go digging around to find it, let's ask
  796. // the compiler configuration. This will allow for projects with long classpaths where classpaths
  797. // are also capturing project dependencies - when a project we depend on is rebuilt, we can just check
  798. // it as a standalone element on our classpath rather than going through them all
  799. List<String> modifiedCpElements = newConfig.getClasspathElementsWithModifiedContents();
  800. for (String modifiedCpElement : modifiedCpElements) {
  801. File cpElement = new File(modifiedCpElement);
  802. if (cpElement.exists() && !cpElement.isDirectory()) {
  803. if (cpElement.lastModified() > lastSuccessfulBuildTime) {
  804. return true;
  805. }
  806. } else {
  807. int classFileChanges = classFileChangedInDirSinceLastBuildRequiringFullBuild(cpElement, PATHID_CLASSPATH);
  808. if (classFileChanges == CLASS_FILE_CHANGED_THAT_NEEDS_FULL_BUILD) {
  809. return true;
  810. }
  811. }
  812. }
  813. }
  814. return false;
  815. }
  816. /**
  817. * Return a list of the output locations - this includes any 'default' output location and then any known by a registered
  818. * CompilationResultDestinationManager.
  819. *
  820. * @param config the build configuration for which the output locations should be determined
  821. * @return a list of file objects
  822. */
  823. private List<File> getOutputLocations(AjBuildConfig config) {
  824. List<File> outputLocs = new ArrayList<>();
  825. // Is there a default location?
  826. if (config.getOutputDir() != null) {
  827. try {
  828. outputLocs.add(config.getOutputDir().getCanonicalFile());
  829. } catch (IOException e) {
  830. }
  831. }
  832. if (config.getCompilationResultDestinationManager() != null) {
  833. List<File> dirs = config.getCompilationResultDestinationManager().getAllOutputLocations();
  834. for (File f : dirs) {
  835. try {
  836. File cf = f.getCanonicalFile();
  837. if (!outputLocs.contains(cf)) {
  838. outputLocs.add(cf);
  839. }
  840. } catch (IOException e) {
  841. }
  842. }
  843. }
  844. return outputLocs;
  845. }
  846. private File getOutputLocationFor(AjBuildConfig config, File aResourceFile) {
  847. if (config.getCompilationResultDestinationManager() != null) {
  848. File outputLoc = config.getCompilationResultDestinationManager().getOutputLocationForResource(aResourceFile);
  849. if (outputLoc != null) {
  850. return outputLoc;
  851. }
  852. }
  853. // Is there a default location?
  854. if (config.getOutputDir() != null) {
  855. return config.getOutputDir();
  856. }
  857. return null;
  858. }
  859. /**
  860. * Check the old and new paths, if they vary by length or individual elements then that is considered a change. Or if the last
  861. * modified time of a path entry has changed (or last modified time of a classfile in that path entry has changed) then return
  862. * true. The outputlocations are supplied so they can be 'ignored' in the comparison.
  863. *
  864. * @param oldPath
  865. * @param newPath
  866. * @param checkClassFiles whether to examine individual class files within directories
  867. * @param outputLocs the output locations that should be ignored if they occur on the paths being compared
  868. * @return true if a change is detected that requires a full build
  869. */
  870. private boolean changedAndNeedsFullBuild(List oldPath, List newPath, boolean checkClassFiles, List<File> outputLocs,
  871. Set<String> alreadyAnalysedPaths, int pathid) {
  872. if (oldPath.size() != newPath.size()) {
  873. return true;
  874. }
  875. for (int i = 0; i < oldPath.size(); i++) {
  876. if (!oldPath.get(i).equals(newPath.get(i))) {
  877. return true;
  878. }
  879. Object o = oldPath.get(i); // String on classpath, File on other paths
  880. File f = null;
  881. if (o instanceof String) {
  882. f = new File((String) o);
  883. } else {
  884. f = (File) o;
  885. }
  886. if (f.exists() && !f.isDirectory() && (f.lastModified() >= lastSuccessfulBuildTime)) {
  887. return true;
  888. }
  889. if (checkClassFiles && f.exists() && f.isDirectory()) {
  890. // We should use here a list/set of directories we know have or have not changed - some kind of
  891. // List<File> buildConfig.getClasspathEntriesWithChangedContents()
  892. // and then only proceed to look inside directories if it is one of these, ignoring others -
  893. // that should save a massive amount of processing for incremental builds in a multi project scenario
  894. boolean foundMatch = false;
  895. for (Iterator<File> iterator = outputLocs.iterator(); !foundMatch && iterator.hasNext();) {
  896. File dir = iterator.next();
  897. if (f.equals(dir)) {
  898. foundMatch = true;
  899. }
  900. }
  901. if (!foundMatch) {
  902. if (!alreadyAnalysedPaths.contains(f.getAbsolutePath())) { // Do not check paths more than once
  903. alreadyAnalysedPaths.add(f.getAbsolutePath());
  904. int classFileChanges = classFileChangedInDirSinceLastBuildRequiringFullBuild(f, pathid);
  905. if (classFileChanges == CLASS_FILE_CHANGED_THAT_NEEDS_FULL_BUILD) {
  906. return true;
  907. }
  908. }
  909. }
  910. }
  911. }
  912. return false;
  913. }
  914. /**
  915. * Check the old and new paths, if they vary by length or individual elements then that is considered a change. Or if the last
  916. * modified time of a path entry has changed (or last modified time of a classfile in that path entry has changed) then return
  917. * true. The outputlocations are supplied so they can be 'ignored' in the comparison.
  918. *
  919. * @param oldPath
  920. * @param newPath
  921. * @param checkClassFiles whether to examine individual class files within directories
  922. * @param outputLocs the output locations that should be ignored if they occur on the paths being compared
  923. * @return true if a change is detected that requires a full build
  924. */
  925. private boolean classpathChangedAndNeedsFullBuild(List<String> oldPath, List<String> newPath, boolean checkClassFiles,
  926. List<File> outputLocs, Set<String> alreadyAnalysedPaths) {
  927. if (oldPath.size() != newPath.size()) {
  928. return true;
  929. }
  930. for (int i = 0; i < oldPath.size(); i++) {
  931. if (!oldPath.get(i).equals(newPath.get(i))) {
  932. return true;
  933. }
  934. File f = new File(oldPath.get(i));
  935. if (f.exists() && !f.isDirectory() && (f.lastModified() >= lastSuccessfulBuildTime)) {
  936. return true;
  937. }
  938. if (checkClassFiles && f.exists() && f.isDirectory()) {
  939. // We should use here a list/set of directories we know have or have not changed - some kind of
  940. // List<File> buildConfig.getClasspathEntriesWithChangedContents()
  941. // and then only proceed to look inside directories if it is one of these, ignoring others -
  942. // that should save a massive amount of processing for incremental builds in a multi project scenario
  943. boolean foundMatch = false;
  944. for (Iterator<File> iterator = outputLocs.iterator(); !foundMatch && iterator.hasNext();) {
  945. File dir = iterator.next();
  946. if (f.equals(dir)) {
  947. foundMatch = true;
  948. }
  949. }
  950. if (!foundMatch) {
  951. if (!alreadyAnalysedPaths.contains(f.getAbsolutePath())) { // Do not check paths more than once
  952. alreadyAnalysedPaths.add(f.getAbsolutePath());
  953. int classFileChanges = classFileChangedInDirSinceLastBuildRequiringFullBuild(f, PATHID_CLASSPATH);
  954. if (classFileChanges == CLASS_FILE_CHANGED_THAT_NEEDS_FULL_BUILD) {
  955. return true;
  956. }
  957. }
  958. }
  959. }
  960. }
  961. return false;
  962. }
  963. public Set<File> getFilesToCompile(boolean firstPass) {
  964. Set<File> thisTime = new HashSet<>();
  965. if (firstPass) {
  966. compiledSourceFiles = new HashSet<>();
  967. Collection<File> modifiedFiles = getModifiedFiles();
  968. // System.out.println("modified: " + modifiedFiles);
  969. thisTime.addAll(modifiedFiles);
  970. // ??? eclipse IncrementalImageBuilder appears to do this
  971. // for (Iterator i = modifiedFiles.iterator(); i.hasNext();) {
  972. // File file = (File) i.next();
  973. // addDependentsOf(file);
  974. // }
  975. if (addedFiles != null) {
  976. for (File o : addedFiles) {
  977. // TODO isn't it a set?? why do this
  978. if (!thisTime.contains(o)) {
  979. thisTime.add(o);
  980. }
  981. }
  982. // thisTime.addAll(addedFiles);
  983. }
  984. deleteClassFiles();
  985. // Do not delete resources on incremental build, AJDT will handle
  986. // copying updates to the output folder. AspectJ only does a copy
  987. // of them on full build (see copyResourcesToDestination() call
  988. // in AjBuildManager)
  989. // deleteResources();
  990. addAffectedSourceFiles(thisTime, thisTime);
  991. } else {
  992. addAffectedSourceFiles(thisTime, compiledSourceFiles);
  993. }
  994. compiledSourceFiles = thisTime;
  995. return thisTime;
  996. }
  997. private boolean maybeIncremental() {
  998. return (FORCE_INCREMENTAL_DURING_TESTING || this.couldBeSubsequentIncrementalBuild);
  999. }
  1000. public Map<String, List<UnwovenClassFile>> getBinaryFilesToCompile(boolean firstTime) {
  1001. if (lastSuccessfulBuildTime == -1 || buildConfig == null || !maybeIncremental()) {
  1002. return binarySourceFiles;
  1003. }
  1004. // else incremental...
  1005. Map<String, List<UnwovenClassFile>> toWeave = new HashMap<>();
  1006. if (firstTime) {
  1007. List<BinarySourceFile> addedOrModified = new ArrayList<>();
  1008. addedOrModified.addAll(addedBinaryFiles);
  1009. addedOrModified.addAll(getModifiedBinaryFiles());
  1010. for (BinarySourceFile bsf : addedOrModified) {
  1011. UnwovenClassFile ucf = createUnwovenClassFile(bsf);
  1012. if (ucf == null) {
  1013. continue;
  1014. }
  1015. List<UnwovenClassFile> ucfs = new ArrayList<>();
  1016. ucfs.add(ucf);
  1017. recordTypeChanged(ucf.getClassName());
  1018. binarySourceFiles.put(bsf.binSrc.getPath(), ucfs);
  1019. List<ClassFile> cfs = new ArrayList<>(1);
  1020. cfs.add(getClassFileFor(ucf));
  1021. this.inputClassFilesBySource.put(bsf.binSrc.getPath(), cfs);
  1022. toWeave.put(bsf.binSrc.getPath(), ucfs);
  1023. }
  1024. deleteBinaryClassFiles();
  1025. } else {
  1026. // return empty set... we've already done our bit.
  1027. }
  1028. return toWeave;
  1029. }
  1030. /**
  1031. * Called when a path change is about to trigger a full build, but we haven't cleaned up from the last incremental build...
  1032. */
  1033. private void removeAllResultsOfLastBuild() {
  1034. // remove all binarySourceFiles, and all classesFromName...
  1035. for (List<ClassFile> cfs : this.inputClassFilesBySource.values()) {
  1036. for (ClassFile cf : cfs) {
  1037. cf.deleteFromFileSystem(buildConfig);
  1038. }
  1039. }
  1040. for (File f : classesFromName.values()) {
  1041. new ClassFile("", f).deleteFromFileSystem(buildConfig);
  1042. }
  1043. Set<Map.Entry<String, File>> resourceEntries = resources.entrySet();
  1044. for (Map.Entry<String, File> resourcePair : resourceEntries) {
  1045. File sourcePath = resourcePair.getValue();
  1046. File outputLoc = getOutputLocationFor(buildConfig, sourcePath);
  1047. if (outputLoc != null) {
  1048. outputLoc = new File(outputLoc, resourcePair.getKey());
  1049. if (!outputLoc.getPath().equals(sourcePath.getPath()) && outputLoc.exists()) {
  1050. outputLoc.delete();
  1051. if (buildConfig.getCompilationResultDestinationManager() != null) {
  1052. buildConfig.getCompilationResultDestinationManager().reportFileRemove(outputLoc.getPath(),
  1053. CompilationResultDestinationManager.FILETYPE_RESOURCE);
  1054. }
  1055. }
  1056. }
  1057. }
  1058. }
  1059. private void deleteClassFiles() {
  1060. if (deletedFiles == null) {
  1061. return;
  1062. }
  1063. for (File deletedFile : deletedFiles) {
  1064. addDependentsOf(deletedFile);
  1065. List<ClassFile> cfs = this.fullyQualifiedTypeNamesResultingFromCompilationUnit.get(deletedFile);
  1066. this.fullyQualifiedTypeNamesResultingFromCompilationUnit.remove(deletedFile);
  1067. if (cfs != null) {
  1068. for (ClassFile cf : cfs) {
  1069. deleteClassFile(cf);
  1070. }
  1071. }
  1072. }
  1073. }
  1074. private void deleteBinaryClassFiles() {
  1075. // range of bsf is ucfs, domain is files (.class and jars) in inpath/jars
  1076. for (BinarySourceFile deletedFile : deletedBinaryFiles) {
  1077. List<ClassFile> cfs = this.inputClassFilesBySource.get(deletedFile.binSrc.getPath());
  1078. for (ClassFile cf : cfs) {
  1079. deleteClassFile(cf);
  1080. }
  1081. this.inputClassFilesBySource.remove(deletedFile.binSrc.getPath());
  1082. }
  1083. }
  1084. // private void deleteResources() {
  1085. // List oldResources = new ArrayList();
  1086. // oldResources.addAll(resources);
  1087. //
  1088. // // note - this deliberately ignores resources in jars as we don't yet handle jar changes
  1089. // // with incremental compilation
  1090. // for (Iterator i = buildConfig.getInpath().iterator(); i.hasNext();) {
  1091. // File inPathElement = (File) i.next();
  1092. // if (inPathElement.isDirectory() && AjBuildManager.COPY_INPATH_DIR_RESOURCES) {
  1093. // deleteResourcesFromDirectory(inPathElement, oldResources);
  1094. // }
  1095. // }
  1096. //
  1097. // if (buildConfig.getSourcePathResources() != null) {
  1098. // for (Iterator i = buildConfig.getSourcePathResources().keySet().iterator(); i.hasNext();) {
  1099. // String resource = (String) i.next();
  1100. // maybeDeleteResource(resource, oldResources);
  1101. // }
  1102. // }
  1103. //
  1104. // // oldResources need to be deleted...
  1105. // for (Iterator iter = oldResources.iterator(); iter.hasNext();) {
  1106. // String victim = (String) iter.next();
  1107. // List outputDirs = getOutputLocations(buildConfig);
  1108. // for (Iterator iterator = outputDirs.iterator(); iterator.hasNext();) {
  1109. // File dir = (File) iterator.next();
  1110. // File f = new File(dir, victim);
  1111. // if (f.exists()) {
  1112. // f.delete();
  1113. // }
  1114. // resources.remove(victim);
  1115. // }
  1116. // }
  1117. // }
  1118. // private void maybeDeleteResource(String resName, List oldResources) {
  1119. // if (resources.contains(resName)) {
  1120. // oldResources.remove(resName);
  1121. // List outputDirs = getOutputLocations(buildConfig);
  1122. // for (Iterator iterator = outputDirs.iterator(); iterator.hasNext();) {
  1123. // File dir = (File) iterator.next();
  1124. // File source = new File(dir, resName);
  1125. // if (source.exists() && (source.lastModified() >= lastSuccessfulBuildTime)) {
  1126. // resources.remove(resName); // will ensure it is re-copied
  1127. // }
  1128. // }
  1129. // }
  1130. // }
  1131. // private void deleteResourcesFromDirectory(File dir, List oldResources) {
  1132. // File[] files = FileUtil.listFiles(dir, new FileFilter() {
  1133. // public boolean accept(File f) {
  1134. // boolean accept = !(f.isDirectory() || f.getName().endsWith(".class"));
  1135. // return accept;
  1136. // }
  1137. // });
  1138. //
  1139. // // For each file, add it either as a real .class file or as a resource
  1140. // for (int i = 0; i < files.length; i++) {
  1141. // // ASSERT: files[i].getAbsolutePath().startsWith(inFile.getAbsolutePath()
  1142. // // or we are in trouble...
  1143. // String filename = null;
  1144. // try {
  1145. // filename = files[i].getCanonicalPath().substring(dir.getCanonicalPath().length() + 1);
  1146. // } catch (IOException e) {
  1147. // // we are in trouble if this happens...
  1148. // IMessage msg = new Message("call to getCanonicalPath() failed for file " + files[i] + " with: " + e.getMessage(),
  1149. // new SourceLocation(files[i], 0), false);
  1150. // buildManager.handler.handleMessage(msg);
  1151. // filename = files[i].getAbsolutePath().substring(dir.getAbsolutePath().length() + 1);
  1152. // }
  1153. //
  1154. // maybeDeleteResource(filename, oldResources);
  1155. // }
  1156. // }
  1157. private void deleteClassFile(ClassFile cf) {
  1158. classesFromName.remove(cf.fullyQualifiedTypeName);
  1159. weaver.deleteClassFile(cf.fullyQualifiedTypeName);
  1160. cf.deleteFromFileSystem(buildConfig);
  1161. }
  1162. private UnwovenClassFile createUnwovenClassFile(AjBuildConfig.BinarySourceFile bsf) {
  1163. UnwovenClassFile ucf = null;
  1164. try {
  1165. File outputDir = buildConfig.getOutputDir();
  1166. if (buildConfig.getCompilationResultDestinationManager() != null) {
  1167. // createUnwovenClassFile is called only for classes that are on the inpath,
  1168. // all inpath classes are put in the defaultOutputLocation, therefore,
  1169. // this is the output dir
  1170. outputDir = buildConfig.getCompilationResultDestinationManager().getDefaultOutputLocation();
  1171. }
  1172. ucf = weaver.addClassFile(bsf.binSrc, bsf.fromInPathDirectory, outputDir);
  1173. } catch (IOException ex) {
  1174. IMessage msg = new Message("can't read class file " + bsf.binSrc.getPath(), new SourceLocation(bsf.binSrc, 0), false);
  1175. buildManager.handler.handleMessage(msg);
  1176. }
  1177. return ucf;
  1178. }
  1179. public void noteResult(InterimCompilationResult result) {
  1180. if (!maybeIncremental()) {
  1181. return;
  1182. }
  1183. File sourceFile = new File(result.fileName());
  1184. CompilationResult cr = result.result();
  1185. references.put(sourceFile, new ReferenceCollection(cr.qualifiedReferences, cr.simpleNameReferences,cr.rootReferences));
  1186. UnwovenClassFile[] unwovenClassFiles = result.unwovenClassFiles();
  1187. for (UnwovenClassFile unwovenClassFile : unwovenClassFiles) {
  1188. File lastTimeRound = classesFromName.get(unwovenClassFile.getClassName());
  1189. recordClassFile(unwovenClassFile, lastTimeRound);
  1190. String name = unwovenClassFile.getClassName();
  1191. if (lastTimeRound == null) {
  1192. deltaAddedClasses.add(name);
  1193. }
  1194. classesFromName.put(name, new File(unwovenClassFile.getFilename()));
  1195. }
  1196. // need to do this before types are deleted from the World...
  1197. recordWhetherCompilationUnitDefinedAspect(sourceFile, cr);
  1198. deleteTypesThatWereInThisCompilationUnitLastTimeRoundButHaveBeenDeletedInThisIncrement(sourceFile, unwovenClassFiles);
  1199. recordFQNsResultingFromCompilationUnit(sourceFile, result);
  1200. }
  1201. public void noteNewResult(CompilationResult cr) {
  1202. // if (!maybeIncremental()) {
  1203. // return;
  1204. // }
  1205. //
  1206. // // File sourceFile = new File(result.fileName());
  1207. // // CompilationResult cr = result.result();
  1208. // if (new String(cr.getFileName()).indexOf("C") != -1) {
  1209. // cr.references.put(new String(cr.getFileName()),
  1210. // new ReferenceCollection(cr.qualifiedReferences, cr.simpleNameReferences));
  1211. // int stop = 1;
  1212. // }
  1213. // references.put(sourceFile, new ReferenceCollection(cr.qualifiedReferences, cr.simpleNameReferences));
  1214. //
  1215. // UnwovenClassFile[] unwovenClassFiles = cr.unwovenClassFiles();
  1216. // for (int i = 0; i < unwovenClassFiles.length; i++) {
  1217. // File lastTimeRound = (File) classesFromName.get(unwovenClassFiles[i].getClassName());
  1218. // recordClassFile(unwovenClassFiles[i], lastTimeRound);
  1219. // classesFromName.put(unwovenClassFiles[i].getClassName(), new File(unwovenClassFiles[i].getFilename()));
  1220. // }
  1221. // need to do this before types are deleted from the World...
  1222. // recordWhetherCompilationUnitDefinedAspect(sourceFile, cr);
  1223. // deleteTypesThatWereInThisCompilationUnitLastTimeRoundButHaveBeenDeletedInThisIncrement(sourceFile, unwovenClassFiles);
  1224. //
  1225. // recordFQNsResultingFromCompilationUnit(sourceFile, result);
  1226. }
  1227. /**
  1228. * @param sourceFile
  1229. * @param unwovenClassFiles
  1230. */
  1231. private void deleteTypesThatWereInThisCompilationUnitLastTimeRoundButHaveBeenDeletedInThisIncrement(File sourceFile,
  1232. UnwovenClassFile[] unwovenClassFiles) {
  1233. List<ClassFile> classFiles = this.fullyQualifiedTypeNamesResultingFromCompilationUnit.get(sourceFile);
  1234. if (classFiles != null) {
  1235. for (UnwovenClassFile unwovenClassFile : unwovenClassFiles) {
  1236. // deleting also deletes types from the weaver... don't do this if they are
  1237. // still present this time around...
  1238. removeFromClassFilesIfPresent(unwovenClassFile.getClassName(), classFiles);
  1239. }
  1240. for (ClassFile cf : classFiles) {
  1241. recordTypeChanged(cf.fullyQualifiedTypeName);
  1242. resolvedTypeStructuresFromLastBuild.remove(cf.fullyQualifiedTypeName);
  1243. // }
  1244. // for (ClassFile cf : classFiles) {
  1245. deleteClassFile(cf);
  1246. }
  1247. }
  1248. }
  1249. private void removeFromClassFilesIfPresent(String className, List<ClassFile> classFiles) {
  1250. ClassFile victim = null;
  1251. for (ClassFile cf : classFiles) {
  1252. if (cf.fullyQualifiedTypeName.equals(className)) {
  1253. victim = cf;
  1254. break;
  1255. }
  1256. }
  1257. if (victim != null) {
  1258. classFiles.remove(victim);
  1259. }
  1260. }
  1261. /**
  1262. * Record the fully-qualified names of the types that were declared in the given source file.
  1263. *
  1264. * @param sourceFile, the compilation unit
  1265. * @param icr, the CompilationResult from compiling it
  1266. */
  1267. private void recordFQNsResultingFromCompilationUnit(File sourceFile, InterimCompilationResult icr) {
  1268. List<ClassFile> classFiles = new ArrayList<>();
  1269. UnwovenClassFile[] types = icr.unwovenClassFiles();
  1270. for (UnwovenClassFile type : types) {
  1271. classFiles.add(new ClassFile(type.getClassName(), new File(type.getFilename())));
  1272. }
  1273. this.fullyQualifiedTypeNamesResultingFromCompilationUnit.put(sourceFile, classFiles);
  1274. }
  1275. /**
  1276. * If this compilation unit defined an aspect, we need to know in case it is modified in a future increment.
  1277. *
  1278. * @param sourceFile
  1279. * @param cr
  1280. */
  1281. private void recordWhetherCompilationUnitDefinedAspect(File sourceFile, CompilationResult cr) {
  1282. this.sourceFilesDefiningAspects.remove(sourceFile);
  1283. if (cr != null) {
  1284. Map compiledTypes = cr.compiledTypes;
  1285. if (compiledTypes != null) {
  1286. for (char[] className : (Iterable<char[]>) compiledTypes.keySet()) {
  1287. String typeName = new String(className).replace('/', '.');
  1288. if (!typeName.contains(BcelWeaver.SYNTHETIC_CLASS_POSTFIX)) {
  1289. ResolvedType rt = world.resolve(typeName);
  1290. if (rt.isMissing()) {
  1291. // This can happen in a case where another problem has occurred that prevented it being
  1292. // correctly added to the world. Eg. pr148285. Duplicate types
  1293. // throw new IllegalStateException("Type '" + rt.getSignature() + "' not found in world!");
  1294. } else if (rt.isAspect()) {
  1295. this.sourceFilesDefiningAspects.add(sourceFile);
  1296. break;
  1297. }
  1298. }
  1299. }
  1300. }
  1301. }
  1302. }
  1303. // private UnwovenClassFile removeFromPreviousIfPresent(UnwovenClassFile cf, InterimCompilationResult previous) {
  1304. // if (previous == null)
  1305. // return null;
  1306. // UnwovenClassFile[] unwovenClassFiles = previous.unwovenClassFiles();
  1307. // for (int i = 0; i < unwovenClassFiles.length; i++) {
  1308. // UnwovenClassFile candidate = unwovenClassFiles[i];
  1309. // if ((candidate != null) && candidate.getFilename().equals(cf.getFilename())) {
  1310. // unwovenClassFiles[i] = null;
  1311. // return candidate;
  1312. // }
  1313. // }
  1314. // return null;
  1315. // }
  1316. private void recordClassFile(UnwovenClassFile thisTime, File lastTime) {
  1317. if (simpleStrings == null) {
  1318. // batch build
  1319. // record resolved type for structural comparisons in future increments
  1320. // this records a second reference to a structure already held in memory
  1321. // by the world.
  1322. ResolvedType rType = world.resolve(thisTime.getClassName());
  1323. if (!rType.isMissing()) {
  1324. try {
  1325. ClassFileReader reader = new ClassFileReader(thisTime.getBytes(), null);
  1326. boolean isAspect = false;
  1327. if (rType instanceof ReferenceType && ((ReferenceType) rType).getDelegate() != null) {
  1328. isAspect = ((ReferenceType) rType).isAspect();
  1329. }
  1330. this.resolvedTypeStructuresFromLastBuild.put(thisTime.getClassName(), new CompactTypeStructureRepresentation(
  1331. reader, isAspect));
  1332. } catch (ClassFormatException cfe) {
  1333. throw new BCException("Unexpected problem processing class", cfe);
  1334. }
  1335. }
  1336. return;
  1337. }
  1338. CompactTypeStructureRepresentation existingStructure = this.resolvedTypeStructuresFromLastBuild
  1339. .get(thisTime.getClassName());
  1340. ResolvedType newResolvedType = world.resolve(thisTime.getClassName());
  1341. if (!newResolvedType.isMissing()) {
  1342. try {
  1343. ClassFileReader reader = new ClassFileReader(thisTime.getBytes(), null);
  1344. boolean isAspect = false;
  1345. if (newResolvedType instanceof ReferenceType && ((ReferenceType) newResolvedType).getDelegate() != null) {
  1346. isAspect = ((ReferenceType) newResolvedType).isAspect();
  1347. }
  1348. this.resolvedTypeStructuresFromLastBuild.put(thisTime.getClassName(), new CompactTypeStructureRepresentation(
  1349. reader, isAspect));
  1350. } catch (ClassFormatException cfe) {
  1351. try {
  1352. String s = System.getProperty("aspectj.debug377096","false");
  1353. if (s.equalsIgnoreCase("true")) {
  1354. String location = System.getProperty("java.io.tmpdir","/tmp");
  1355. String name = thisTime.getClassName();
  1356. File f = File.createTempFile(location+File.separator+name, ".class");
  1357. StringBuilder debug = new StringBuilder();
  1358. debug.append("Debug377096: Dumping class called "+name+" to "+f.getName()+" size:"+thisTime.getBytes().length);
  1359. DataOutputStream dos = new DataOutputStream(new FileOutputStream(f));
  1360. dos.write(thisTime.getBytes());
  1361. dos.close();
  1362. throw new BCException(debug.toString(), cfe);
  1363. }
  1364. } catch (Exception e) {
  1365. e.printStackTrace();
  1366. }
  1367. throw new BCException("Unexpected problem processing class", cfe);
  1368. }
  1369. }
  1370. if (lastTime == null) {
  1371. recordTypeChanged(thisTime.getClassName());
  1372. return;
  1373. }
  1374. if (newResolvedType.isMissing()) {
  1375. return;
  1376. }
  1377. world.ensureAdvancedConfigurationProcessed();
  1378. byte[] newBytes = thisTime.getBytes();
  1379. try {
  1380. ClassFileReader reader = new ClassFileReader(newBytes, lastTime.getAbsolutePath().toCharArray());
  1381. // ignore local types since they're only visible inside a single method
  1382. if (!(reader.isLocal() || reader.isAnonymous())) {
  1383. if (hasStructuralChanges(reader, existingStructure)) {
  1384. if (listenerDefined()) {
  1385. // if (world.forDEBUG_structuralChangesCode) {
  1386. // System.err.println("Detected a structural change in " + thisTime.getFilename());
  1387. printStructuralChanges(thisTime.getFilename(),reader, existingStructure);
  1388. }
  1389. structuralChangesSinceLastFullBuild.put(thisTime.getFilename(), currentBuildTime);
  1390. recordTypeChanged(new String(reader.getName()).replace('/', '.'));
  1391. }
  1392. }
  1393. } catch (ClassFormatException e) {
  1394. recordTypeChanged(thisTime.getClassName());
  1395. }
  1396. }
  1397. /**
  1398. * Compare the class structure of the new intermediate (unwoven) class with the existingResolvedType of the same class that we
  1399. * have in the world, looking for any structural differences (and ignoring aj members resulting from weaving....)
  1400. *
  1401. * Some notes from Andy... lot of problems here, which I've eventually resolved by building the compactstructure based on a
  1402. * classfilereader, rather than on a ResolvedType. There are accessors for inner types and funky fields that the compiler
  1403. * creates to support the language - for non-static inner types it also mangles ctors to be prefixed with an instance of the
  1404. * surrounding type.
  1405. *
  1406. * @param reader
  1407. * @param existingType
  1408. * @return
  1409. */
  1410. private boolean hasStructuralChanges(ClassFileReader reader, CompactTypeStructureRepresentation existingType) {
  1411. if (existingType == null) {
  1412. return true;
  1413. }
  1414. // modifiers
  1415. if (!modifiersEqual(reader.getModifiers(), existingType.modifiers)) {
  1416. return true;
  1417. }
  1418. // generic signature
  1419. if (!CharOperation.equals(reader.getGenericSignature(), existingType.genericSignature)) {
  1420. return true;
  1421. }
  1422. // superclass name
  1423. if (!CharOperation.equals(reader.getSuperclassName(), existingType.superclassName)) {
  1424. return true;
  1425. }
  1426. // have annotations changed on the type?
  1427. IBinaryAnnotation[] newAnnos = reader.getAnnotations();
  1428. if (newAnnos == null || newAnnos.length == 0) {
  1429. if (existingType.annotations != null && existingType.annotations.length != 0) {
  1430. return true;
  1431. }
  1432. } else {
  1433. IBinaryAnnotation[] existingAnnos = existingType.annotations;
  1434. if (existingAnnos == null || existingAnnos.length != newAnnos.length) {
  1435. return true;
  1436. }
  1437. // Does not allow for an order switch
  1438. // Does not cope with a change in values set on the annotation (hard to create a testcase where this is a problem tho)
  1439. for (int i = 0; i < newAnnos.length; i++) {
  1440. if (!CharOperation.equals(newAnnos[i].getTypeName(), existingAnnos[i].getTypeName())) {
  1441. return true;
  1442. }
  1443. }
  1444. }
  1445. // interfaces
  1446. char[][] existingIfs = existingType.interfaces;
  1447. char[][] newIfsAsChars = reader.getInterfaceNames();
  1448. if (newIfsAsChars == null) {
  1449. newIfsAsChars = EMPTY_CHAR_ARRAY;
  1450. } // damn I'm lazy...
  1451. if (existingIfs == null) {
  1452. existingIfs = EMPTY_CHAR_ARRAY;
  1453. }
  1454. if (existingIfs.length != newIfsAsChars.length) {
  1455. return true;
  1456. }
  1457. new_interface_loop:
  1458. for (char[] newIfsAsChar : newIfsAsChars) {
  1459. for (char[] existingIf : existingIfs) {
  1460. if (CharOperation.equals(existingIf, newIfsAsChar)) {
  1461. continue new_interface_loop;
  1462. }
  1463. }
  1464. return true;
  1465. }
  1466. // fields
  1467. // CompactMemberStructureRepresentation[] existingFields = existingType.fields;
  1468. IBinaryField[] newFields = reader.getFields();
  1469. if (newFields == null) {
  1470. newFields = CompactTypeStructureRepresentation.NoField;
  1471. }
  1472. // all redundant for now ... could be an optimization at some point...
  1473. // remove any ajc$XXX fields from those we compare with
  1474. // the existing fields - bug 129163
  1475. // List nonGenFields = new ArrayList();
  1476. // for (int i = 0; i < newFields.length; i++) {
  1477. // IBinaryField field = newFields[i];
  1478. // //if (!CharOperation.prefixEquals(NameMangler.AJC_DOLLAR_PREFIX,field.getName())) { // this would skip ajc$ fields
  1479. // //if ((field.getModifiers()&0x1000)==0) // 0x1000 => synthetic - this will skip synthetic fields (eg. this$0)
  1480. // nonGenFields.add(field);
  1481. // //}
  1482. // }
  1483. IBinaryField[] existingFs = existingType.binFields;
  1484. if (newFields.length != existingFs.length) {
  1485. return true;
  1486. }
  1487. new_field_loop:
  1488. for (IBinaryField field : newFields) {
  1489. char[] fieldName = field.getName();
  1490. for (IBinaryField existingF : existingFs) {
  1491. if (CharOperation.equals(existingF.getName(), fieldName)) {
  1492. IBinaryField existing = existingF;
  1493. if (!modifiersEqual(field.getModifiers(), existing.getModifiers())) {
  1494. return true;
  1495. }
  1496. if (!CharOperation.equals(existing.getTypeName(), field.getTypeName())) {
  1497. return true;
  1498. }
  1499. char[] existingGSig = existing.getGenericSignature();
  1500. char[] fieldGSig = field.getGenericSignature();
  1501. if ((existingGSig == null && fieldGSig != null) || (existingGSig != null && fieldGSig == null)) {
  1502. return true;
  1503. }
  1504. if (existingGSig != null) {
  1505. if (!CharOperation.equals(existingGSig, fieldGSig)) {
  1506. return true;
  1507. }
  1508. }
  1509. continue new_field_loop;
  1510. }
  1511. }
  1512. return true;
  1513. }
  1514. // methods
  1515. // CompactMemberStructureRepresentation[] existingMethods = existingType.methods;
  1516. IBinaryMethod[] newMethods = reader.getMethods();
  1517. if (newMethods == null) {
  1518. newMethods = CompactTypeStructureRepresentation.NoMethod;
  1519. }
  1520. // all redundant for now ... could be an optimization at some point...
  1521. // Ctors in a non-static inner type have an 'extra parameter' of the enclosing type.
  1522. // If skippableDescriptorPrefix gets set here then it is set to the descriptor portion
  1523. // for this 'extra parameter'. For an inner class of pkg.Foo the skippable descriptor
  1524. // prefix will be '(Lpkg/Foo;' - so later when comparing <init> methods we know what to
  1525. // compare.
  1526. // IF THIS CODE NEEDS TO GET MORE COMPLICATED, I THINK ITS WORTH RIPPING IT ALL OUT AND
  1527. // CREATING THE STRUCTURAL CHANGES OBJECT BASED ON CLASSREADER OUTPUT RATHER THAN
  1528. // THE RESOLVEDTYPE - THEN THERE WOULD BE NO NEED TO TREAT SOME METHODS IN A PECULIAR
  1529. // WAY.
  1530. // char[] skippableDescriptorPrefix = null;
  1531. // char[] enclosingTypeName = reader.getEnclosingTypeName();
  1532. // boolean isStaticType = Modifier.isStatic(reader.getModifiers());
  1533. // if (!isStaticType && enclosingTypeName!=null) {
  1534. // StringBuffer sb = new StringBuffer();
  1535. // sb.append("(L").append(new String(enclosingTypeName)).append(";");
  1536. // skippableDescriptorPrefix = sb.toString().toCharArray();
  1537. // }
  1538. //
  1539. //
  1540. // // remove the aspectOf, hasAspect, clinit and ajc$XXX methods
  1541. // // from those we compare with the existing methods - bug 129163
  1542. // List nonGenMethods = new ArrayList();
  1543. // for (int i = 0; i < newMethods.length; i++) {
  1544. // IBinaryMethod method = newMethods[i];
  1545. // // if ((method.getModifiers() & 0x1000)!=0) continue; // 0x1000 => synthetic - will cause us to skip access$0 - is this
  1546. // always safe?
  1547. // char[] methodName = method.getSelector();
  1548. // // if (!CharOperation.equals(methodName,NameMangler.METHOD_ASPECTOF) &&
  1549. // // !CharOperation.equals(methodName,NameMangler.METHOD_HASASPECT) &&
  1550. // // !CharOperation.equals(methodName,NameMangler.STATIC_INITIALIZER) &&
  1551. // // !CharOperation.prefixEquals(NameMangler.AJC_DOLLAR_PREFIX,methodName) &&
  1552. // // !CharOperation.prefixEquals(NameMangler.CLINIT,methodName)) {
  1553. // nonGenMethods.add(method);
  1554. // // }
  1555. // }
  1556. IBinaryMethod[] existingMs = existingType.binMethods;
  1557. if (newMethods.length != existingMs.length) {
  1558. return true;
  1559. }
  1560. new_method_loop:
  1561. for (IBinaryMethod method : newMethods) {
  1562. char[] methodName = method.getSelector();
  1563. for (IBinaryMethod existingM : existingMs) {
  1564. if (CharOperation.equals(existingM.getSelector(), methodName)) {
  1565. // candidate match
  1566. if (!CharOperation.equals(method.getMethodDescriptor(), existingM.getMethodDescriptor())) {
  1567. // ok, the descriptors don't match, but is this a funky ctor on a non-static inner
  1568. // type?
  1569. // boolean mightBeOK =
  1570. // skippableDescriptorPrefix!=null && // set for inner types
  1571. // CharOperation.equals(methodName,NameMangler.INIT) && // ctor
  1572. // CharOperation.prefixEquals(skippableDescriptorPrefix,method.getMethodDescriptor()); // checking for
  1573. // prefix on the descriptor
  1574. // if (mightBeOK) {
  1575. // // OK, so the descriptor starts something like '(Lpkg/Foo;' - we now may need to look at the rest of the
  1576. // // descriptor if it takes >1 parameter.
  1577. // // eg. could be (Lpkg/C;Ljava/lang/String;) where the skippablePrefix is (Lpkg/C;
  1578. // char [] md = method.getMethodDescriptor();
  1579. // char[] remainder = CharOperation.subarray(md, skippableDescriptorPrefix.length, md.length);
  1580. // if (CharOperation.equals(remainder,BRACKET_V)) continue new_method_loop; // no other parameters to worry
  1581. // about
  1582. // char[] comparableSig = CharOperation.subarray(existingMethods[j].signature, 1,
  1583. // existingMethods[j].signature.length);
  1584. // boolean match = CharOperation.equals(comparableSig, remainder);
  1585. // if (match) continue new_method_loop;
  1586. // }
  1587. continue; // might be overloading
  1588. } else {
  1589. // matching sigs
  1590. IBinaryMethod existing = existingM;
  1591. if (!modifiersEqual(method.getModifiers(), existing.getModifiers())) {
  1592. return true;
  1593. }
  1594. if (exceptionClausesDiffer(existing, method)) {
  1595. return true;
  1596. }
  1597. char[] existingGSig = existing.getGenericSignature();
  1598. char[] methodGSig = method.getGenericSignature();
  1599. if ((existingGSig == null && methodGSig != null) || (existingGSig != null && methodGSig == null)) {
  1600. return true;
  1601. }
  1602. if (existingGSig != null) {
  1603. if (!CharOperation.equals(existingGSig, methodGSig)) {
  1604. return true;
  1605. }
  1606. }
  1607. continue new_method_loop;
  1608. }
  1609. }
  1610. }
  1611. return true; // (no match found)
  1612. }
  1613. // check for differences in inner types
  1614. // TODO could make order insensitive
  1615. IBinaryNestedType[] binaryNestedTypes = reader.getMemberTypes();
  1616. IBinaryNestedType[] existingBinaryNestedTypes = existingType.getMemberTypes();
  1617. if ((binaryNestedTypes == null && existingBinaryNestedTypes != null)
  1618. || (binaryNestedTypes != null && existingBinaryNestedTypes == null)) {
  1619. return true;
  1620. }
  1621. if (binaryNestedTypes != null) {
  1622. int bnLength = binaryNestedTypes.length;
  1623. if (existingBinaryNestedTypes.length != bnLength) {
  1624. return true;
  1625. }
  1626. for (int m = 0; m < bnLength; m++) {
  1627. IBinaryNestedType bnt = binaryNestedTypes[m];
  1628. IBinaryNestedType existingBnt = existingBinaryNestedTypes[m];
  1629. if (!CharOperation.equals(bnt.getName(), existingBnt.getName())) {
  1630. return true;
  1631. }
  1632. }
  1633. }
  1634. return false;
  1635. }
  1636. private void logAnalysis(String filename, String info) {
  1637. if (listenerDefined()) {
  1638. getListener().recordDecision("StructuralAnalysis["+filename+"]: "+info);
  1639. }
  1640. }
  1641. private boolean printStructuralChanges(String filename, ClassFileReader reader, CompactTypeStructureRepresentation existingType) {
  1642. logAnalysis(filename,"appears to have structurally changed, printing changes:");
  1643. if (existingType == null) {
  1644. logAnalysis(filename,"have not seen this type before");
  1645. return true;
  1646. }
  1647. // modifiers
  1648. if (!modifiersEqual(reader.getModifiers(), existingType.modifiers)) {
  1649. logAnalysis(filename,"modifiers changed. old=0x"+Integer.toHexString(existingType.getModifiers())+" new=0x"+Integer.toHexString(reader.getModifiers()));
  1650. return true;
  1651. }
  1652. // generic signature
  1653. if (!CharOperation.equals(reader.getGenericSignature(), existingType.genericSignature)) {
  1654. logAnalysis(filename,"generic signature changed. old="+stringify(existingType.genericSignature)+" new="+stringify(reader.getGenericSignature()));
  1655. return true;
  1656. }
  1657. // superclass name
  1658. if (!CharOperation.equals(reader.getSuperclassName(), existingType.superclassName)) {
  1659. logAnalysis(filename,"superclass name changed. old="+stringify(existingType.superclassName)+" new="+stringify(reader.getSuperclassName()));
  1660. return true;
  1661. }
  1662. // have annotations changed on the type?
  1663. IBinaryAnnotation[] newAnnos = reader.getAnnotations();
  1664. if (newAnnos == null || newAnnos.length == 0) {
  1665. if (existingType.annotations != null && existingType.annotations.length != 0) {
  1666. logAnalysis(filename,"type used to have annotations and now does not: "+stringify(existingType.annotations));
  1667. return true;
  1668. }
  1669. } else {
  1670. IBinaryAnnotation[] existingAnnos = existingType.annotations;
  1671. if (existingAnnos == null || existingAnnos.length != newAnnos.length) {
  1672. logAnalysis(filename,"type now has annotations which it did not used to have: "+stringify(newAnnos));
  1673. return true;
  1674. }
  1675. // Does not allow for an order switch
  1676. // Does not cope with a change in values set on the annotation (hard to create a testcase where this is a problem tho)
  1677. for (int i = 0; i < newAnnos.length; i++) {
  1678. if (!CharOperation.equals(newAnnos[i].getTypeName(), existingAnnos[i].getTypeName())) {
  1679. logAnalysis(filename,"type annotation change at position "+i+" old="+new String(existingAnnos[i].getTypeName())+" new="+new String(newAnnos[i].getTypeName()));
  1680. return true;
  1681. }
  1682. }
  1683. }
  1684. // interfaces
  1685. char[][] existingIfs = existingType.interfaces;
  1686. char[][] newIfsAsChars = reader.getInterfaceNames();
  1687. if (newIfsAsChars == null) {
  1688. newIfsAsChars = EMPTY_CHAR_ARRAY;
  1689. } // damn I'm lazy...
  1690. if (existingIfs == null) {
  1691. existingIfs = EMPTY_CHAR_ARRAY;
  1692. }
  1693. if (existingIfs.length != newIfsAsChars.length) {
  1694. return true;
  1695. }
  1696. new_interface_loop:
  1697. for (char[] newIfsAsChar : newIfsAsChars) {
  1698. for (char[] existingIf : existingIfs) {
  1699. if (CharOperation.equals(existingIf, newIfsAsChar)) {
  1700. continue new_interface_loop;
  1701. }
  1702. }
  1703. logAnalysis(filename, "set of interfaces changed. old=" + stringify(existingIfs) + " new=" + stringify(newIfsAsChars));
  1704. return true;
  1705. }
  1706. // fields
  1707. // CompactMemberStructureRepresentation[] existingFields = existingType.fields;
  1708. IBinaryField[] newFields = reader.getFields();
  1709. if (newFields == null) {
  1710. newFields = CompactTypeStructureRepresentation.NoField;
  1711. }
  1712. // all redundant for now ... could be an optimization at some point...
  1713. // remove any ajc$XXX fields from those we compare with
  1714. // the existing fields - bug 129163
  1715. // List nonGenFields = new ArrayList();
  1716. // for (int i = 0; i < newFields.length; i++) {
  1717. // IBinaryField field = newFields[i];
  1718. // //if (!CharOperation.prefixEquals(NameMangler.AJC_DOLLAR_PREFIX,field.getName())) { // this would skip ajc$ fields
  1719. // //if ((field.getModifiers()&0x1000)==0) // 0x1000 => synthetic - this will skip synthetic fields (eg. this$0)
  1720. // nonGenFields.add(field);
  1721. // //}
  1722. // }
  1723. IBinaryField[] existingFs = existingType.binFields;
  1724. if (newFields.length != existingFs.length) {
  1725. logAnalysis(filename,"number of fields changed. old="+stringify(existingFs)+" new="+stringify(newFields));
  1726. return true;
  1727. }
  1728. new_field_loop:
  1729. for (IBinaryField field : newFields) {
  1730. char[] fieldName = field.getName();
  1731. for (IBinaryField existingF : existingFs) {
  1732. if (CharOperation.equals(existingF.getName(), fieldName)) {
  1733. IBinaryField existing = existingF;
  1734. if (!modifiersEqual(field.getModifiers(), existing.getModifiers())) {
  1735. logAnalysis(filename, "field modifiers changed '" + existing + "' old=0x" + Integer.toHexString(existing.getModifiers()) + " new=0x" + Integer.toHexString(field.getModifiers()));
  1736. return true;
  1737. }
  1738. if (!CharOperation.equals(existing.getTypeName(), field.getTypeName())) {
  1739. logAnalysis(filename, "field type changed '" + existing + "' old=" + new String(existing.getTypeName()) + " new=" + new String(field.getTypeName()));
  1740. return true;
  1741. }
  1742. char[] existingGSig = existing.getGenericSignature();
  1743. char[] fieldGSig = field.getGenericSignature();
  1744. if ((existingGSig == null && fieldGSig != null) || (existingGSig != null && fieldGSig == null)) {
  1745. logAnalysis(filename, "field generic sig changed '" + existing + "' old=" +
  1746. (existingGSig == null ? "null" : new String(existingGSig)) + " new=" + (fieldGSig == null ? "null" : new String(fieldGSig)));
  1747. return true;
  1748. }
  1749. if (existingGSig != null) {
  1750. if (!CharOperation.equals(existingGSig, fieldGSig)) {
  1751. logAnalysis(filename, "field generic sig changed '" + existing + "' old=" +
  1752. (existingGSig == null ? "null" : new String(existingGSig)) + " new=" + (fieldGSig == null ? "null" : new String(fieldGSig)));
  1753. return true;
  1754. }
  1755. }
  1756. continue new_field_loop;
  1757. }
  1758. }
  1759. logAnalysis(filename, "field changed. New field detected '" + field + "'");
  1760. return true;
  1761. }
  1762. // methods
  1763. // CompactMemberStructureRepresentation[] existingMethods = existingType.methods;
  1764. IBinaryMethod[] newMethods = reader.getMethods();
  1765. if (newMethods == null) {
  1766. newMethods = CompactTypeStructureRepresentation.NoMethod;
  1767. }
  1768. // all redundant for now ... could be an optimization at some point...
  1769. // Ctors in a non-static inner type have an 'extra parameter' of the enclosing type.
  1770. // If skippableDescriptorPrefix gets set here then it is set to the descriptor portion
  1771. // for this 'extra parameter'. For an inner class of pkg.Foo the skippable descriptor
  1772. // prefix will be '(Lpkg/Foo;' - so later when comparing <init> methods we know what to
  1773. // compare.
  1774. // IF THIS CODE NEEDS TO GET MORE COMPLICATED, I THINK ITS WORTH RIPPING IT ALL OUT AND
  1775. // CREATING THE STRUCTURAL CHANGES OBJECT BASED ON CLASSREADER OUTPUT RATHER THAN
  1776. // THE RESOLVEDTYPE - THEN THERE WOULD BE NO NEED TO TREAT SOME METHODS IN A PECULIAR
  1777. // WAY.
  1778. // char[] skippableDescriptorPrefix = null;
  1779. // char[] enclosingTypeName = reader.getEnclosingTypeName();
  1780. // boolean isStaticType = Modifier.isStatic(reader.getModifiers());
  1781. // if (!isStaticType && enclosingTypeName!=null) {
  1782. // StringBuffer sb = new StringBuffer();
  1783. // sb.append("(L").append(new String(enclosingTypeName)).append(";");
  1784. // skippableDescriptorPrefix = sb.toString().toCharArray();
  1785. // }
  1786. //
  1787. //
  1788. // // remove the aspectOf, hasAspect, clinit and ajc$XXX methods
  1789. // // from those we compare with the existing methods - bug 129163
  1790. // List nonGenMethods = new ArrayList();
  1791. // for (int i = 0; i < newMethods.length; i++) {
  1792. // IBinaryMethod method = newMethods[i];
  1793. // // if ((method.getModifiers() & 0x1000)!=0) continue; // 0x1000 => synthetic - will cause us to skip access$0 - is this
  1794. // always safe?
  1795. // char[] methodName = method.getSelector();
  1796. // // if (!CharOperation.equals(methodName,NameMangler.METHOD_ASPECTOF) &&
  1797. // // !CharOperation.equals(methodName,NameMangler.METHOD_HASASPECT) &&
  1798. // // !CharOperation.equals(methodName,NameMangler.STATIC_INITIALIZER) &&
  1799. // // !CharOperation.prefixEquals(NameMangler.AJC_DOLLAR_PREFIX,methodName) &&
  1800. // // !CharOperation.prefixEquals(NameMangler.CLINIT,methodName)) {
  1801. // nonGenMethods.add(method);
  1802. // // }
  1803. // }
  1804. IBinaryMethod[] existingMs = existingType.binMethods;
  1805. if (newMethods.length != existingMs.length) {
  1806. logAnalysis(filename,"number of methods changed. old="+stringify(existingMs)+" new="+stringify(newMethods));
  1807. return true;
  1808. }
  1809. new_method_loop:
  1810. for (IBinaryMethod method : newMethods) {
  1811. char[] methodName = method.getSelector();
  1812. for (IBinaryMethod existingM : existingMs) {
  1813. if (CharOperation.equals(existingM.getSelector(), methodName)) {
  1814. // candidate match
  1815. if (!CharOperation.equals(method.getMethodDescriptor(), existingM.getMethodDescriptor())) {
  1816. // ok, the descriptors don't match, but is this a funky ctor on a non-static inner
  1817. // type?
  1818. // boolean mightBeOK =
  1819. // skippableDescriptorPrefix!=null && // set for inner types
  1820. // CharOperation.equals(methodName,NameMangler.INIT) && // ctor
  1821. // CharOperation.prefixEquals(skippableDescriptorPrefix,method.getMethodDescriptor()); // checking for
  1822. // prefix on the descriptor
  1823. // if (mightBeOK) {
  1824. // // OK, so the descriptor starts something like '(Lpkg/Foo;' - we now may need to look at the rest of the
  1825. // // descriptor if it takes >1 parameter.
  1826. // // eg. could be (Lpkg/C;Ljava/lang/String;) where the skippablePrefix is (Lpkg/C;
  1827. // char [] md = method.getMethodDescriptor();
  1828. // char[] remainder = CharOperation.subarray(md, skippableDescriptorPrefix.length, md.length);
  1829. // if (CharOperation.equals(remainder,BRACKET_V)) continue new_method_loop; // no other parameters to worry
  1830. // about
  1831. // char[] comparableSig = CharOperation.subarray(existingMethods[j].signature, 1,
  1832. // existingMethods[j].signature.length);
  1833. // boolean match = CharOperation.equals(comparableSig, remainder);
  1834. // if (match) continue new_method_loop;
  1835. // }
  1836. continue; // might be overloading
  1837. } else {
  1838. // matching sigs
  1839. IBinaryMethod existing = existingM;
  1840. if (!modifiersEqual(method.getModifiers(), existing.getModifiers())) {
  1841. logAnalysis(filename, "method modifiers changed '" + existing + "' old=0x" + Integer.toHexString(existing.getModifiers()) + " new=0x" + Integer.toHexString(method.getModifiers()));
  1842. return true;
  1843. }
  1844. if (exceptionClausesDiffer(existing, method)) {
  1845. logAnalysis(filename, "method exception clauses changed '" + existing + "' old=" + existing + " new=" + method);
  1846. return true;
  1847. }
  1848. char[] existingGSig = existing.getGenericSignature();
  1849. char[] methodGSig = method.getGenericSignature();
  1850. if ((existingGSig == null && methodGSig != null) || (existingGSig != null && methodGSig == null)) {
  1851. logAnalysis(filename, "method generic sig changed '" + existing + "' old=" +
  1852. (existingGSig == null ? "null" : new String(existingGSig)) + " new=" + (methodGSig == null ? "null" : new String(methodGSig)));
  1853. return true;
  1854. }
  1855. if (existingGSig != null) {
  1856. if (!CharOperation.equals(existingGSig, methodGSig)) {
  1857. logAnalysis(filename, "method generic sig changed '" + existing + "' old=" +
  1858. (existingGSig == null ? "null" : new String(existingGSig)) + " new=" + (methodGSig == null ? "null" : new String(methodGSig)));
  1859. return true;
  1860. }
  1861. }
  1862. continue new_method_loop;
  1863. }
  1864. }
  1865. // TODO missing a return true here? Meaning we have a field in the new that we can't find in the old!
  1866. }
  1867. logAnalysis(filename, "method changed. New method detected '" + stringify(method) + "' (might be a rename)");
  1868. return true; // (no match found)
  1869. }
  1870. // check for differences in inner types
  1871. // TODO could make order insensitive
  1872. IBinaryNestedType[] binaryNestedTypes = reader.getMemberTypes();
  1873. IBinaryNestedType[] existingBinaryNestedTypes = existingType.getMemberTypes();
  1874. if ((binaryNestedTypes == null && existingBinaryNestedTypes != null)
  1875. || (binaryNestedTypes != null && existingBinaryNestedTypes == null)) {
  1876. logAnalysis(filename,"nested types changed");
  1877. return true;
  1878. }
  1879. if (binaryNestedTypes != null) {
  1880. int bnLength = binaryNestedTypes.length;
  1881. if (existingBinaryNestedTypes.length != bnLength) {
  1882. logAnalysis(filename,"nested types changed. old="+stringify(existingBinaryNestedTypes)+" new="+stringify(binaryNestedTypes));
  1883. return true;
  1884. }
  1885. for (int m = 0; m < bnLength; m++) {
  1886. IBinaryNestedType bnt = binaryNestedTypes[m];
  1887. IBinaryNestedType existingBnt = existingBinaryNestedTypes[m];
  1888. if (!CharOperation.equals(bnt.getName(), existingBnt.getName())) {
  1889. logAnalysis(filename,"nested type changed name at position "+m+" old="+stringify(existingBinaryNestedTypes)+" new="+stringify(binaryNestedTypes));
  1890. return true;
  1891. }
  1892. }
  1893. }
  1894. return false;
  1895. }
  1896. private String stringify(char[] chars) {
  1897. if (chars == null) {
  1898. return "null";
  1899. }
  1900. return new String(chars);
  1901. }
  1902. private String stringify(IBinaryNestedType[] binaryNestedTypes) {
  1903. StringBuilder buf = new StringBuilder();
  1904. for (IBinaryNestedType binaryNestedType: binaryNestedTypes) {
  1905. buf.append(binaryNestedType).append(" ");
  1906. }
  1907. return buf.toString().trim();
  1908. }
  1909. private String stringify(IBinaryMethod[] methods) {
  1910. StringBuilder buf = new StringBuilder();
  1911. for (IBinaryMethod method: methods) {
  1912. buf.append(stringify(method)).append(" ");
  1913. }
  1914. return "["+buf.toString().trim()+"]";
  1915. }
  1916. private String stringify(IBinaryMethod m) {
  1917. StringBuilder buf = new StringBuilder();
  1918. buf.append("0x").append(Integer.toHexString(m.getModifiers())).append(" ");
  1919. buf.append(m.getSelector()).append(m.getMethodDescriptor());
  1920. // IBinaryAnnotation[] annos = m.getAnnotations();
  1921. // TODO include annotations, generic sig, etc
  1922. return buf.toString().trim();
  1923. }
  1924. private String stringify(IBinaryField[] fields) {
  1925. StringBuilder buf = new StringBuilder();
  1926. for (IBinaryField field: fields) {
  1927. buf.append(stringify(field)).append(" ");
  1928. }
  1929. return "["+buf.toString().trim()+"]";
  1930. }
  1931. private Object stringify(IBinaryField f) {
  1932. StringBuilder buf = new StringBuilder();
  1933. buf.append("0x").append(Integer.toHexString(f.getModifiers())).append(" ");
  1934. buf.append(f.getTypeName()).append(f.getName());
  1935. return buf.toString().trim();
  1936. }
  1937. private String stringify(char[][] arrayOfCharArrays) {
  1938. StringBuilder buf = new StringBuilder();
  1939. for (char[] charArray: arrayOfCharArrays) {
  1940. buf.append(charArray).append(" ");
  1941. }
  1942. return buf.toString().trim();
  1943. }
  1944. private String stringify(IBinaryAnnotation[] annotations) {
  1945. StringBuilder buf = new StringBuilder();
  1946. for (IBinaryAnnotation anno: annotations) {
  1947. buf.append(anno).append(" ");
  1948. }
  1949. return buf.toString().trim();
  1950. }
  1951. /**
  1952. * For two methods, discover if there has been a change in the exception types specified.
  1953. *
  1954. * @return true if the exception types have changed
  1955. */
  1956. private boolean exceptionClausesDiffer(IBinaryMethod lastMethod, IBinaryMethod newMethod) {
  1957. char[][] previousExceptionTypeNames = lastMethod.getExceptionTypeNames();
  1958. char[][] newExceptionTypeNames = newMethod.getExceptionTypeNames();
  1959. int pLength = previousExceptionTypeNames.length;
  1960. int nLength = newExceptionTypeNames.length;
  1961. if (pLength != nLength) {
  1962. return true;
  1963. }
  1964. if (pLength == 0) {
  1965. return false;
  1966. }
  1967. // TODO could be insensitive to an order change
  1968. for (int i = 0; i < pLength; i++) {
  1969. if (!CharOperation.equals(previousExceptionTypeNames[i], newExceptionTypeNames[i])) {
  1970. return true;
  1971. }
  1972. }
  1973. return false;
  1974. }
  1975. private boolean modifiersEqual(int eclipseModifiers, int resolvedTypeModifiers) {
  1976. resolvedTypeModifiers = resolvedTypeModifiers & ExtraCompilerModifiers.AccJustFlag;
  1977. eclipseModifiers = eclipseModifiers & ExtraCompilerModifiers.AccJustFlag;
  1978. // if ((eclipseModifiers & CompilerModifiers.AccSuper) != 0) {
  1979. // eclipseModifiers -= CompilerModifiers.AccSuper;
  1980. // }
  1981. return (eclipseModifiers == resolvedTypeModifiers);
  1982. }
  1983. // private static StringSet makeStringSet(List strings) {
  1984. // StringSet ret = new StringSet(strings.size());
  1985. // for (Iterator iter = strings.iterator(); iter.hasNext();) {
  1986. // String element = (String) iter.next();
  1987. // ret.add(element);
  1988. // }
  1989. // return ret;
  1990. // }
  1991. private String stringifySet(Set<?> l) {
  1992. StringBuilder sb = new StringBuilder();
  1993. sb.append("{");
  1994. for (Iterator<?> iter = l.iterator(); iter.hasNext();) {
  1995. Object el = iter.next();
  1996. sb.append(el);
  1997. if (iter.hasNext()) {
  1998. sb.append(",");
  1999. }
  2000. }
  2001. sb.append("}");
  2002. return sb.toString();
  2003. }
  2004. protected void addAffectedSourceFiles(Set<File> addTo, Set<File> lastTimeSources) {
  2005. if (qualifiedStrings.elementSize == 0 && simpleStrings.elementSize == 0) {
  2006. return;
  2007. }
  2008. if (listenerDefined()) {
  2009. getListener().recordDecision(
  2010. "Examining whether any other files now need compilation based on just compiling: '"
  2011. + stringifySet(lastTimeSources) + "'");
  2012. }
  2013. // the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
  2014. char[][][] qualifiedNames = ReferenceCollection.internQualifiedNames(qualifiedStrings);
  2015. // if a well known qualified name was found then we can skip over these
  2016. if (qualifiedNames.length < qualifiedStrings.elementSize) {
  2017. qualifiedNames = null;
  2018. }
  2019. char[][] simpleNames = ReferenceCollection.internSimpleNames(simpleStrings, true);
  2020. // if a well known name was found then we can skip over these
  2021. if (simpleNames.length < simpleStrings.elementSize) {
  2022. simpleNames = null;
  2023. }
  2024. // System.err.println("simple: " + simpleStrings);
  2025. // System.err.println("qualif: " + qualifiedStrings);
  2026. for (Map.Entry<File, ReferenceCollection> entry : references.entrySet()) {
  2027. ReferenceCollection refs = entry.getValue();
  2028. if (refs != null && refs.includes(qualifiedNames, simpleNames)) {
  2029. File file = entry.getKey();
  2030. if (file.exists()) {
  2031. if (!lastTimeSources.contains(file)) { // ??? O(n**2)
  2032. if (listenerDefined()) {
  2033. getListener().recordDecision("Need to recompile '" + file.getName().toString() + "'");
  2034. }
  2035. addTo.add(file);
  2036. }
  2037. }
  2038. }
  2039. }
  2040. // add in the things we compiled previously - I know that seems crap but otherwise we may pull woven
  2041. // stuff off disk (since we no longer have UnwovenClassFile objects) in order to satisfy references
  2042. // in the new files we are about to compile (see pr133532)
  2043. if (addTo.size() > 0) {
  2044. addTo.addAll(lastTimeSources);
  2045. }
  2046. // // XXX Promote addTo to a Set - then we don't need this rubbish? but does it need to be ordered?
  2047. // if (addTo.size()>0) {
  2048. // for (Iterator iter = lastTimeSources.iterator(); iter.hasNext();) {
  2049. // Object element = (Object) iter.next();
  2050. // if (!addTo.contains(element)) addTo.add(element);
  2051. // }
  2052. // }
  2053. qualifiedStrings.clear();
  2054. simpleStrings.clear();
  2055. }
  2056. /**
  2057. * Record that a particular type has been touched during a compilation run. Information is used to ensure any types depending
  2058. * upon this one are also recompiled.
  2059. *
  2060. * @param typename (possibly qualified) type name
  2061. */
  2062. protected void recordTypeChanged(String typename) {
  2063. int lastDot = typename.lastIndexOf('.');
  2064. String typeName;
  2065. if (lastDot != -1) {
  2066. String packageName = typename.substring(0, lastDot).replace('.', '/');
  2067. qualifiedStrings.add(packageName);
  2068. typeName = typename.substring(lastDot + 1);
  2069. } else {
  2070. qualifiedStrings.add("");
  2071. typeName = typename;
  2072. }
  2073. int memberIndex = typeName.indexOf('$');
  2074. if (memberIndex > 0) {
  2075. typeName = typeName.substring(0, memberIndex);
  2076. }
  2077. simpleStrings.add(typeName);
  2078. }
  2079. /**
  2080. * Record some additional dependencies between types. When any of the types specified in fullyQualifiedTypeNames changes, we
  2081. * need to recompile the file named in the CompilationResult. This method patches that information into the existing data
  2082. * structures.
  2083. */
  2084. public boolean recordDependencies(File file, String[] typeNameDependencies) {
  2085. try {
  2086. File sourceFile = new File(new String(file.getCanonicalPath()));
  2087. ReferenceCollection existingCollection = references.get(sourceFile);
  2088. if (existingCollection != null) {
  2089. existingCollection.addDependencies(typeNameDependencies);
  2090. return true;
  2091. } else {
  2092. ReferenceCollection rc = new ReferenceCollection(null, null, null);
  2093. rc.addDependencies(typeNameDependencies);
  2094. references.put(sourceFile, rc);
  2095. return true;
  2096. }
  2097. } catch (IOException ioe) {
  2098. ioe.printStackTrace();
  2099. }
  2100. return false;
  2101. }
  2102. protected void addDependentsOf(File sourceFile) {
  2103. List<ClassFile> cfs = this.fullyQualifiedTypeNamesResultingFromCompilationUnit.get(sourceFile);
  2104. if (cfs != null) {
  2105. for (ClassFile cf : cfs) {
  2106. recordTypeChanged(cf.fullyQualifiedTypeName);
  2107. }
  2108. }
  2109. }
  2110. public void setStructureModel(AsmManager structureModel) {
  2111. this.structureModel = structureModel;
  2112. }
  2113. public AsmManager getStructureModel() {
  2114. return structureModel;
  2115. }
  2116. public void setWeaver(BcelWeaver bw) {
  2117. weaver = bw;
  2118. }
  2119. public BcelWeaver getWeaver() {
  2120. return weaver;
  2121. }
  2122. public void setWorld(BcelWorld bw) {
  2123. world = bw;
  2124. world.addTypeDelegateResolver(this);
  2125. }
  2126. public BcelWorld getBcelWorld() {
  2127. return world;
  2128. }
  2129. //
  2130. // public void setRelationshipMap(IRelationshipMap irm) {
  2131. // relmap = irm;
  2132. // }
  2133. //
  2134. // public IRelationshipMap getRelationshipMap() {
  2135. // return relmap;
  2136. // }
  2137. public int getNumberOfStructuralChangesSinceLastFullBuild() {
  2138. return structuralChangesSinceLastFullBuild.size();
  2139. }
  2140. /** Returns last time we did a full or incremental build. */
  2141. public long getLastBuildTime() {
  2142. return lastSuccessfulBuildTime;
  2143. }
  2144. /** Returns last time we did a full build */
  2145. public long getLastFullBuildTime() {
  2146. return lastSuccessfulFullBuildTime;
  2147. }
  2148. /**
  2149. * @return Returns the buildConfig.
  2150. */
  2151. public AjBuildConfig getBuildConfig() {
  2152. return this.buildConfig;
  2153. }
  2154. public void clearBinarySourceFiles() {
  2155. this.binarySourceFiles = new HashMap<>();
  2156. }
  2157. public void recordBinarySource(String fromPathName, List<UnwovenClassFile> unwovenClassFiles) {
  2158. this.binarySourceFiles.put(fromPathName, unwovenClassFiles);
  2159. if (this.maybeIncremental()) {
  2160. List<ClassFile> simpleClassFiles = new LinkedList<>();
  2161. for (UnwovenClassFile ucf : unwovenClassFiles) {
  2162. ClassFile cf = getClassFileFor(ucf);
  2163. simpleClassFiles.add(cf);
  2164. }
  2165. this.inputClassFilesBySource.put(fromPathName, simpleClassFiles);
  2166. }
  2167. }
  2168. /**
  2169. * @param ucf
  2170. * @return
  2171. */
  2172. private ClassFile getClassFileFor(UnwovenClassFile ucf) {
  2173. return new ClassFile(ucf.getClassName(), new File(ucf.getFilename()));
  2174. }
  2175. public Map<String, List<UnwovenClassFile>> getBinarySourceMap() {
  2176. return this.binarySourceFiles;
  2177. }
  2178. public Map<String, File> getClassNameToFileMap() {
  2179. return this.classesFromName;
  2180. }
  2181. public boolean hasResource(String resourceName) {
  2182. return this.resources.keySet().contains(resourceName);
  2183. }
  2184. public void recordResource(String resourceName, File resourceSourceLocation) {
  2185. this.resources.put(resourceName, resourceSourceLocation);
  2186. }
  2187. /**
  2188. * @return Returns the addedFiles.
  2189. */
  2190. public Set<File> getAddedFiles() {
  2191. return this.addedFiles;
  2192. }
  2193. /**
  2194. * @return Returns the deletedFiles.
  2195. */
  2196. public Set<File> getDeletedFiles() {
  2197. return this.deletedFiles;
  2198. }
  2199. public void forceBatchBuildNextTimeAround() {
  2200. this.batchBuildRequiredThisTime = true;
  2201. }
  2202. public boolean requiresFullBatchBuild() {
  2203. return this.batchBuildRequiredThisTime;
  2204. }
  2205. private static class ClassFile {
  2206. public String fullyQualifiedTypeName;
  2207. public File locationOnDisk;
  2208. public ClassFile(String fqn, File location) {
  2209. this.fullyQualifiedTypeName = fqn;
  2210. this.locationOnDisk = location;
  2211. }
  2212. @Override
  2213. public String toString() {
  2214. StringBuilder s = new StringBuilder();
  2215. s.append("ClassFile(type=").append(fullyQualifiedTypeName).append(",location=").append(locationOnDisk).append(")");
  2216. return s.toString();
  2217. }
  2218. public void deleteFromFileSystem(AjBuildConfig buildConfig) {
  2219. String namePrefix = locationOnDisk.getName();
  2220. namePrefix = namePrefix.substring(0, namePrefix.lastIndexOf('.'));
  2221. final String targetPrefix = namePrefix + BcelWeaver.CLOSURE_CLASS_PREFIX;
  2222. File dir = locationOnDisk.getParentFile();
  2223. if (dir != null) {
  2224. File[] weaverGenerated = dir.listFiles(new FilenameFilter() {
  2225. @Override
  2226. public boolean accept(File dir, String name) {
  2227. return name.startsWith(targetPrefix);
  2228. }
  2229. });
  2230. if (weaverGenerated != null) {
  2231. for (File file : weaverGenerated) {
  2232. file.delete();
  2233. if (buildConfig != null && buildConfig.getCompilationResultDestinationManager() != null) {
  2234. buildConfig.getCompilationResultDestinationManager().reportFileRemove(file.getPath(),
  2235. CompilationResultDestinationManager.FILETYPE_CLASS);
  2236. }
  2237. }
  2238. }
  2239. }
  2240. locationOnDisk.delete();
  2241. if (buildConfig != null && buildConfig.getCompilationResultDestinationManager() != null) {
  2242. buildConfig.getCompilationResultDestinationManager().reportFileRemove(locationOnDisk.getPath(),
  2243. CompilationResultDestinationManager.FILETYPE_CLASS);
  2244. }
  2245. }
  2246. }
  2247. public void wipeAllKnowledge() {
  2248. buildManager.state = null;
  2249. // buildManager.setStructureModel(null);
  2250. }
  2251. public Map<String, char[]> getAspectNamesToFileNameMap() {
  2252. return aspectsFromFileNames;
  2253. }
  2254. public void initializeAspectNamesToFileNameMap() {
  2255. this.aspectsFromFileNames = new HashMap<>();
  2256. }
  2257. // Will allow us to record decisions made during incremental processing, hopefully aid in debugging
  2258. public boolean listenerDefined() {
  2259. return stateListener != null;
  2260. }
  2261. public IStateListener getListener() {
  2262. return stateListener;
  2263. }
  2264. public IBinaryType checkPreviousBuild(String name) {
  2265. return resolvedTypeStructuresFromLastBuild.get(name);
  2266. }
  2267. public AjBuildManager getAjBuildManager() {
  2268. return buildManager;
  2269. }
  2270. public INameEnvironment getNameEnvironment() {
  2271. return this.nameEnvironment;
  2272. }
  2273. public void setNameEnvironment(INameEnvironment nameEnvironment) {
  2274. this.nameEnvironment = nameEnvironment;
  2275. }
  2276. public FileSystem getFileSystem() {
  2277. return this.fileSystem;
  2278. }
  2279. public void setFileSystem(FileSystem fileSystem) {
  2280. this.fileSystem = fileSystem;
  2281. }
  2282. /**
  2283. * Record an aspect that came in on the aspect path. When a .class file changes on the aspect path we can then recognize it as
  2284. * an aspect and know to do more than just a tiny incremental build. <br>
  2285. * TODO but this doesn't allow for a new aspect created on the aspectpath?
  2286. *
  2287. * @param aspectFile path to the file, eg. c:/temp/foo/Fred.class
  2288. */
  2289. public void recordAspectClassFile(String aspectFile) {
  2290. aspectClassFiles.add(aspectFile);
  2291. }
  2292. public void write(CompressingDataOutputStream dos) throws IOException {
  2293. // weaver
  2294. weaver.write(dos);
  2295. // world
  2296. // model
  2297. // local state
  2298. }
  2299. /**
  2300. * See if we can create a delegate from a CompactTypeStructure - TODO better comment
  2301. */
  2302. @Override
  2303. public ReferenceTypeDelegate getDelegate(ReferenceType referenceType) {
  2304. File f = classesFromName.get(referenceType.getName());
  2305. if (f == null) {
  2306. return null; // not heard of it
  2307. }
  2308. try {
  2309. ClassParser parser = new ClassParser(f.toString());
  2310. return world.buildBcelDelegate(referenceType, parser.parse(), true, false);
  2311. } catch (IOException e) {
  2312. IMessage msg = new Message("Failed to recover " + referenceType, referenceType.getDelegate()!=null?referenceType.getSourceLocation():null, false);
  2313. buildManager.handler.handleMessage(msg);
  2314. }
  2315. return null;
  2316. }
  2317. }