PageRenderTime 87ms CodeModel.GetById 16ms app.highlight 66ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/update-engine/externals/google-toolbox-for-mac/XcodePlugin/GTMXcodeGCovItem.m

http://macfuse.googlecode.com/
Objective C | 498 lines | 408 code | 63 blank | 27 comment | 44 complexity | a6f19091bccb2e603ab3adaed0be51ee MD5 | raw file
  1//
  2//  GTMXcodeGCovItem.m
  3//
  4//  Copyright 2007-2009 Google Inc.
  5//
  6//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7//  use this file except in compliance with the License.  You may obtain a copy
  8//  of the License at
  9//
 10//  http://www.apache.org/licenses/LICENSE-2.0
 11//
 12//  Unless required by applicable law or agreed to in writing, software
 13//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 14//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 15//  License for the specific language governing permissions and limitations under
 16//  the License.
 17//
 18
 19#import "GTMXcodeMenuItem.h"
 20#import "GTMXcodePlugin.h"
 21#import "PBXAppDelegate.h"
 22#import "PBXExtendedApplication.h"
 23#import "PBXProject.h"
 24#import "PBXTarget.h"
 25#import "GTMMethodCheck.h"
 26#import "NSTask+Script.h"
 27#import "GTMDefines.h"
 28
 29// Indices for our various menu items
 30enum {
 31  kGTMXcodeGCovSeparatorItemIndex = 19,
 32  kGTMXcodeGCovEnableCoverageItemIndex,
 33  kGTMXcodeGCovCheckCoverageMenuItemIndex,
 34  kGTMXcodeGCovCleanCoverageMenuItemIndex,
 35  kGTMXcodeGCovCleanCoverageAndBuildMenuItemIndex,
 36};
 37
 38// The different methods of open coverage provided.
 39typedef enum {
 40  kGTMXcodeGCovOpenFile,
 41  kGTMXcodeGCovOpenTarget,
 42  kGTMXcodeGCovOpenBuildFolder,
 43} GTMXcodeGCovOpenMode;
 44
 45typedef enum {
 46  kGTMXcodeGCovCleanDataTarget,
 47  kGTMXcodeGCovCleanDataBuildFolder,
 48} GTMXcodeGCovCleanMode;
 49
 50// Some paths that we resolve
 51NSString *const kObjectsDirPath
 52  = @"$(OBJECT_FILE_DIR)-$(BUILD_VARIANTS)";
 53NSString *const kObjectsDirNoArchPath
 54  = @"$(OBJECT_FILE_DIR)-$(BUILD_VARIANTS)";
 55NSString *const kBuildRootDirPath = @"$(BUILD_ROOT)";
 56
 57// the title for our menu items w/ submenus
 58NSString *kShowCodeCoverageForMenuTitle = @"Show Code Coverage For";
 59NSString *kCleanCodeCoverageDataForMenuTitle = @"Clean Code Coverage Data For";
 60
 61// Separator above the GCov menu items
 62@interface GTMXcodeGCovSeparatorItem : GTMXcodeMenuItem
 63@end
 64
 65// Enable Code Coverage menu item
 66@interface GTMXcodeGCovEnableItem : GTMXcodeMenuItem
 67@end
 68
 69// Check coverage for menu
 70@interface GTMXcodeGCovCoverageMenuItem : GTMXcodeMenuItem {
 71  NSString *title_;
 72  int index_;
 73}
 74- (id)initWithTitle:(NSString *)title index:(int)index;
 75@end
 76
 77// Check coverage for option
 78@interface GTMXcodeGCovCheckCoverageItem : GTMXcodeMenuItem {
 79  NSString *title_;
 80  GTMXcodeGCovOpenMode mode_;
 81  int index_;
 82}
 83- (id)initWithTitle:(NSString *)title
 84               mode:(GTMXcodeGCovOpenMode)mode
 85              index:(int)index;
 86@end
 87
 88// Clean coverage data item
 89@interface GTMXcodeGCovCleanItem : GTMXcodeMenuItem {
 90  NSString *title_;
 91  GTMXcodeGCovCleanMode mode_;
 92  int index_;
 93}
 94- (id)initWithTitle:(NSString *)title
 95               mode:(GTMXcodeGCovCleanMode)mode
 96              index:(int)index;
 97@end
 98
 99@interface GTMXcodeGCovCleanAndBuildItem : GTMXcodeMenuItem
100@end
101
102// Category for checking if gcov is enabled on current target
103@interface PBXExtendedApplication (GTMXcodeGCovMenuItemAdditions)
104- (BOOL)gtm_gcovEnabledForActiveTarget;
105@end
106
107@interface NSString (GTMXcodeGCovItem)
108- (BOOL)gtm_isCOrObjCFile;
109@end
110
111@implementation GTMXcodeGCovSeparatorItem
112+ (void)load {
113  [GTMXcodePlugin registerMenuItem:[[[self alloc] init] autorelease]];
114}
115
116- (NSString*)title {
117  return @"-";
118}
119
120- (NSMenu*)insertionMenu {
121  return [[NSApp delegate] buildMenu];
122}
123
124- (int)insertionIndex {
125  return kGTMXcodeGCovSeparatorItemIndex;
126}
127@end
128
129@implementation GTMXcodeGCovCoverageMenuItem
130+ (void)load {
131  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
132  GTMXcodeGCovCoverageMenuItem *item
133    = [[[self alloc] initWithTitle:kShowCodeCoverageForMenuTitle
134                             index:kGTMXcodeGCovCheckCoverageMenuItemIndex]
135       autorelease];
136  [GTMXcodePlugin registerMenuItem:item];
137  item = [[[self alloc] initWithTitle:kCleanCodeCoverageDataForMenuTitle
138                                index:kGTMXcodeGCovCleanCoverageMenuItemIndex]
139          autorelease];
140  [GTMXcodePlugin registerMenuItem:item];
141  [pool release];
142}
143
144- (id)initWithTitle:(NSString *)title index:(int)idx {
145  if ((self = [super init])) {
146    title_ = title;
147    index_ = idx;
148  }
149  return self;
150}
151
152- (NSString*)title {
153  return title_;
154}
155
156- (NSMenu*)insertionMenu {
157  return [[NSApp delegate] buildMenu];
158}
159
160- (int)insertionIndex {
161  return index_;
162}
163
164- (void)wasInserted:(NSMenuItem*)item {
165  NSMenu *menu = [[[NSMenu alloc] initWithTitle:title_] autorelease];
166  [item setSubmenu:menu];
167}
168@end
169
170@implementation GTMXcodeGCovCheckCoverageItem
171GTM_METHOD_CHECK(NSTask, gtm_runScript:withArguments:);
172
173+ (void)load {
174  struct OpenItemDesc {
175    NSString *title;
176    GTMXcodeGCovOpenMode mode;
177    int index;
178  };
179
180  struct OpenItemDesc items [] = {
181    { @"Selected file", kGTMXcodeGCovOpenFile, 0 },
182    { @"Current target", kGTMXcodeGCovOpenTarget, 1 },
183    { @"Current project", kGTMXcodeGCovOpenBuildFolder, 2 },
184  };
185  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
186  for(size_t i = 0; i < sizeof(items) / sizeof(struct OpenItemDesc); ++i) {
187    GTMXcodeGCovCheckCoverageItem *item
188      = [[[self alloc] initWithTitle:items[i].title
189                                mode:items[i].mode
190                               index:items[i].index] autorelease];
191    [GTMXcodePlugin registerMenuItem:item];
192  }
193  [pool release];
194}
195
196- (id)initWithTitle:(NSString *)title
197               mode:(GTMXcodeGCovOpenMode)mode
198              index:(int)idx {
199  if ((self = [super init])) {
200    title_ = title;
201    mode_ = mode;
202    index_ = idx;
203  }
204  return self;
205}
206
207- (NSMenu*)insertionMenu {
208  NSMenu *menu = [[NSApp delegate] buildMenu];
209  NSInteger menuIndex
210    = [menu indexOfItemWithTitle:kShowCodeCoverageForMenuTitle];
211  NSMenuItem *menuItem = [menu itemAtIndex:menuIndex];
212  return [menuItem submenu];
213}
214
215- (NSString*)title {
216  return title_;
217}
218
219- (void)action:(id)sender {
220  NSString *pathToOpen = nil;
221  PBXProject *project = [NSApp currentProject];
222  PBXTarget *target = [project activeTarget];
223  NSString *buildConfig = [project activeBuildConfigurationName];
224  if (mode_ == kGTMXcodeGCovOpenFile) {
225    NSArray *selectedPaths = [self selectedPaths];
226    NSString *selectedPath = nil;
227    if ([selectedPaths count] == 1) {
228      NSString *path = [selectedPaths objectAtIndex:0];
229      if ([path gtm_isCOrObjCFile]) {
230        selectedPath = path;
231      }
232      if (selectedPath) {
233        NSString *srcFileName = [selectedPath lastPathComponent];
234        NSUInteger fileLength = [srcFileName length];
235        NSUInteger extensionLength = [[srcFileName pathExtension] length];
236        NSString *subStr
237          = [srcFileName substringToIndex:(fileLength - extensionLength)];
238        NSString *gcdaFileName = [NSString stringWithFormat:@"%@gcda", subStr];
239        NSString *objectsDir = [self pathByExpandingString:kObjectsDirPath
240                                     forBuildConfiguration:buildConfig
241                                                  ofTarget:target];
242        NSString *activeArchitecture = [project activeArchitecture];
243        NSString *archPath 
244          = [objectsDir stringByAppendingPathComponent:activeArchitecture];
245        NSString *gcdaPath
246          = [archPath stringByAppendingPathComponent:gcdaFileName];
247        pathToOpen = gcdaPath;
248      }
249    }
250  } else if (mode_ == kGTMXcodeGCovOpenTarget) {
251    NSString *objectsDirNoArch 
252      = [self pathByExpandingString:kObjectsDirNoArchPath
253              forBuildConfiguration:buildConfig
254                           ofTarget:target];    
255    pathToOpen = objectsDirNoArch;
256  } else if (mode_ == kGTMXcodeGCovOpenBuildFolder) {
257    NSString *buildRootDir = [self pathByExpandingString:kBuildRootDirPath
258                                   forBuildConfiguration:buildConfig
259                                                ofTarget:target];    
260    pathToOpen = buildRootDir;
261  }
262  if (pathToOpen) {
263    [NSTask gtm_runScript:@"opencoverage" withArguments:pathToOpen, nil];
264  }
265}
266
267- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
268  BOOL isGood = NO;
269  switch (mode_) {
270    case kGTMXcodeGCovOpenFile:
271      if ([NSApp gtm_gcovEnabledForActiveTarget]) {
272        NSArray *selectedPaths = [self selectedPaths];
273        if ([selectedPaths count] == 1) {
274          NSString *path = [selectedPaths objectAtIndex:0];
275          if ([path gtm_isCOrObjCFile]) {
276            isGood = YES;
277          }
278        }
279      }
280      break;
281    case kGTMXcodeGCovOpenTarget:
282      isGood = [NSApp gtm_gcovEnabledForActiveTarget];
283      break;
284    case kGTMXcodeGCovOpenBuildFolder:
285      isGood = ([NSApp currentProject] != nil);
286      break;
287  }
288  return isGood;
289}
290
291- (int)depth {
292  return 2;
293}
294
295- (int)insertionIndex {
296  return index_;
297}
298
299- (BOOL)allowGDTMenuIcon {
300  return NO;
301}
302@end
303
304
305@implementation GTMXcodeGCovEnableItem
306GTM_METHOD_CHECK(NSTask, gtm_runScript:withArguments:);
307+ (void)load {
308  [GTMXcodePlugin registerMenuItem:[[[self alloc] init] autorelease]];
309}
310
311- (NSMenu*)insertionMenu {
312  return [[NSApp delegate] buildMenu];
313}
314
315- (NSString*)title {
316  return @"";
317}
318
319- (void)action:(id)sender {
320  NSString *enabled = [NSApp gtm_gcovEnabledForActiveTarget] ? @"NO" : @"YES";
321  [NSTask gtm_runScript:@"EnableGCov" withArguments:enabled, nil];
322}
323
324- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
325  BOOL isGood = NO;
326  NSString *title = @"Turn Code Coverage On";
327  PBXProject *project = [NSApp currentProject];
328  if (project) {
329    isGood = YES;
330    if ([NSApp gtm_gcovEnabledForActiveTarget]) {
331      title = @"Turn Code Coverage Off";
332    }
333  }
334  [menuItem setTitle:title];
335  return isGood;
336}
337
338- (int)insertionIndex {
339  return kGTMXcodeGCovEnableCoverageItemIndex;
340}
341@end
342
343@implementation GTMXcodeGCovCleanItem
344GTM_METHOD_CHECK(NSTask, gtm_runScript:withArguments:);
345+ (void)load {
346  struct CleanItemDesc {
347    NSString *title;
348    GTMXcodeGCovCleanMode mode;
349    int index;
350  };
351
352  struct CleanItemDesc items [] = {
353    { @"Current target", kGTMXcodeGCovCleanDataTarget, 0 },
354    { @"Current project", kGTMXcodeGCovCleanDataBuildFolder, 1 },
355  };
356
357  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
358  for(size_t i = 0; i < sizeof(items) / sizeof(struct CleanItemDesc); ++i) {
359    GTMXcodeGCovCleanItem *item = [[[self alloc] initWithTitle:items[i].title
360                                                         mode:items[i].mode
361                                                        index:items[i].index]
362                                  autorelease];
363    [GTMXcodePlugin registerMenuItem:item];
364  }
365  [pool release];
366}
367
368- (id)initWithTitle:(NSString *)title
369               mode:(GTMXcodeGCovCleanMode)mode
370              index:(int)idx {
371  if ((self = [super init])) {
372    title_ = title;
373    mode_ = mode;
374    index_ = idx;
375  }
376  return self;
377}
378
379- (NSMenu*)insertionMenu {
380  NSMenu *menu = [[NSApp delegate] buildMenu];
381  NSInteger menuIndex
382    = [menu indexOfItemWithTitle:kCleanCodeCoverageDataForMenuTitle];
383  NSMenuItem *menuItem = [menu itemAtIndex:menuIndex];
384  return [menuItem submenu];
385}
386
387- (NSString*)title {
388  return title_;
389}
390
391- (void)action:(id)sender {
392  NSString *pathToClean = nil;
393  PBXProject *project = [NSApp currentProject];
394  PBXTarget *target = [project activeTarget];
395  NSString *buildConfig = [project activeBuildConfigurationName];
396  if (mode_ == kGTMXcodeGCovCleanDataTarget) {
397    NSString *objectsDirNoArch
398      = [self pathByExpandingString:kObjectsDirNoArchPath
399              forBuildConfiguration:buildConfig
400                           ofTarget:target];    
401    pathToClean = objectsDirNoArch;
402  } else if (mode_ == kGTMXcodeGCovCleanDataBuildFolder) {
403    NSString *buildRootDir = [self pathByExpandingString:kBuildRootDirPath
404                                         forBuildConfiguration:buildConfig
405                                                      ofTarget:target];   
406    pathToClean = buildRootDir;
407  }
408  if (pathToClean) {
409    [NSTask gtm_runScript:@"ResetGCov" withArguments:pathToClean, nil];
410  }
411}
412
413- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
414  BOOL isGood = NO;
415  switch (mode_) {
416    case kGTMXcodeGCovCleanDataTarget:
417      isGood = [NSApp gtm_gcovEnabledForActiveTarget];
418      break;
419    case kGTMXcodeGCovCleanDataBuildFolder:
420      isGood = ([NSApp currentProject] != nil);
421      break;
422  }
423  return isGood;
424}
425
426- (int)depth {
427  return 2;
428}
429
430- (int)insertionIndex {
431  return index_;
432}
433
434- (BOOL)allowGDTMenuIcon {
435  return NO;
436}
437@end
438
439@implementation GTMXcodeGCovCleanAndBuildItem
440+ (void)load {
441  [GTMXcodePlugin registerMenuItem:[[[self alloc] init] autorelease]];
442}
443
444- (NSString*)title {
445  return @"Clean Project Coverage and Build";
446}
447
448- (NSMenu*)insertionMenu {
449  return [[NSApp delegate] buildMenu];
450}
451
452- (int)insertionIndex {
453  return kGTMXcodeGCovCleanCoverageAndBuildMenuItemIndex;
454}
455
456- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
457  return [NSApp gtm_gcovEnabledForActiveTarget];
458}
459
460- (void)action:(id)sender {
461  NSString *pathToClean = nil;
462  PBXProject *project = [NSApp currentProject];
463  PBXTarget *target = [project activeTarget];
464  NSString *buildConfig = [project activeBuildConfigurationName];
465  NSString *buildRootDir = [self pathByExpandingString:kBuildRootDirPath
466                                 forBuildConfiguration:buildConfig
467                                              ofTarget:target];    
468  pathToClean = buildRootDir;
469  if (pathToClean) {
470    [NSTask gtm_runScript:@"CleanCovAndBuild" withArguments:pathToClean, nil];
471  }
472}
473
474@end
475
476@implementation PBXExtendedApplication (GTMXcodeGCovMenuItemAdditions)
477- (BOOL)gtm_gcovEnabledForActiveTarget {
478  BOOL answer = NO;
479  PBXProject *project = [NSApp currentProject];
480  PBXTarget *target = [project activeTarget];
481  NSString *buildConfig = [project activeBuildConfigurationName];
482  if (project && target && buildConfig) {
483    NSString *setting = [target stringByExpandingString:@"$(OTHER_LDFLAGS)"
484                             forBuildConfigurationNamed:buildConfig];
485    answer = [setting rangeOfString:@"-lgcov"].length != 0;
486  }
487  return answer;
488}
489@end
490
491@implementation NSString (GTMXcodeGCovItem)
492- (BOOL)gtm_isCOrObjCFile {
493  return [self hasSuffix:@".c"] || [self hasSuffix:@".cpp"]
494  || [self hasSuffix:@".cc"] || [self hasSuffix:@".cp"]
495  || [self hasSuffix:@".m"] || [self hasSuffix:@".mm"];
496}
497@end
498